Index: experimental/StrokePathRenderer/GrStrokePathRenderer.cpp |
diff --git a/experimental/StrokePathRenderer/GrStrokePathRenderer.cpp b/experimental/StrokePathRenderer/GrStrokePathRenderer.cpp |
deleted file mode 100644 |
index e693c41a6690a73959d118db8c8c4d4827c6db35..0000000000000000000000000000000000000000 |
--- a/experimental/StrokePathRenderer/GrStrokePathRenderer.cpp |
+++ /dev/null |
@@ -1,298 +0,0 @@ |
-/* |
- * 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 "GrStrokePathRenderer.h" |
- |
-#include "GrDrawTarget.h" |
-#include "SkPath.h" |
-#include "SkStrokeRec.h" |
- |
-static bool is_clockwise(const SkVector& before, const SkVector& after) { |
- return before.cross(after) > 0; |
-} |
- |
-enum IntersectionType { |
- kNone_IntersectionType, |
- kIn_IntersectionType, |
- kOut_IntersectionType |
-}; |
- |
-static IntersectionType intersection(const SkPoint& p1, const SkPoint& p2, |
- const SkPoint& p3, const SkPoint& p4, |
- SkPoint& res) { |
- // Store the values for fast access and easy |
- // equations-to-code conversion |
- SkScalar x1 = p1.x(), x2 = p2.x(), x3 = p3.x(), x4 = p4.x(); |
- SkScalar y1 = p1.y(), y2 = p2.y(), y3 = p3.y(), y4 = p4.y(); |
- |
- SkScalar d = SkScalarMul(x1 - x2, y3 - y4) - SkScalarMul(y1 - y2, x3 - x4); |
- // If d is zero, there is no intersection |
- if (SkScalarNearlyZero(d)) { |
- return kNone_IntersectionType; |
- } |
- |
- // Get the x and y |
- SkScalar pre = SkScalarMul(x1, y2) - SkScalarMul(y1, x2), |
- post = SkScalarMul(x3, y4) - SkScalarMul(y3, x4); |
- // Compute the point of intersection |
- res.set((SkScalarMul(pre, x3 - x4) - SkScalarMul(x1 - x2, post) / d, |
- (SkScalarMul(pre, y3 - y4) - SkScalarMul(y1 - y2, post) / d); |
- |
- // Check if the x and y coordinates are within both lines |
- return (res.x() < GrMin(x1, x2) || res.x() > GrMax(x1, x2) || |
- res.x() < GrMin(x3, x4) || res.x() > GrMax(x3, x4) || |
- res.y() < GrMin(y1, y2) || res.y() > GrMax(y1, y2) || |
- res.y() < GrMin(y3, y4) || res.y() > GrMax(y3, y4)) ? |
- kOut_IntersectionType : kIn_IntersectionType; |
-} |
- |
-GrStrokePathRenderer::GrStrokePathRenderer() { |
-} |
- |
-bool GrStrokePathRenderer::canDrawPath(const SkPath& path, |
- const SkStrokeRec& stroke, |
- const GrDrawTarget* target, |
- bool antiAlias) const { |
- // FIXME : put the proper condition once GrDrawTarget::isOpaque is implemented |
- const bool isOpaque = true; // target->isOpaque(); |
- |
- // FIXME : remove this requirement once we have AA circles and implement the |
- // circle joins/caps appropriately in the ::onDrawPath() function. |
- const bool requiresAACircle = (stroke.getCap() == SkPaint::kRound_Cap) || |
- (stroke.getJoin() == SkPaint::kRound_Join); |
- |
- // Indices being stored in uint16, we don't want to overflow the indices capacity |
- static const int maxVBSize = 1 << 16; |
- const int maxNbVerts = (path.countPoints() + 1) * 5; |
- |
- // Check that the path contains no curved lines, only straight lines |
- static const uint32_t unsupportedMask = SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask; |
- |
- // Must not be filled nor hairline nor semi-transparent |
- // Note : May require a check to path.isConvex() if AA is supported |
- return ((stroke.getStyle() == SkStrokeRec::kStroke_Style) && (maxNbVerts < maxVBSize) && |
- !path.isInverseFillType() && isOpaque && !requiresAACircle && !antiAlias && |
- ((path.getSegmentMasks() & unsupportedMask) == 0)); |
-} |
- |
-bool GrStrokePathRenderer::onDrawPath(const SkPath& origPath, |
- const SkStrokeRec& stroke, |
- GrDrawTarget* target, |
- bool antiAlias) { |
- if (origPath.isEmpty()) { |
- return true; |
- } |
- |
- SkScalar width = stroke.getWidth(); |
- if (width <= 0) { |
- return false; |
- } |
- |
- // Get the join type |
- SkPaint::Join join = stroke.getJoin(); |
- SkScalar miterLimit = stroke.getMiter(); |
- SkScalar sqMiterLimit = SkScalarMul(miterLimit, miterLimit); |
- if ((join == SkPaint::kMiter_Join) && (miterLimit <= SK_Scalar1)) { |
- // If the miter limit is small, treat it as a bevel join |
- join = SkPaint::kBevel_Join; |
- } |
- const bool isMiter = (join == SkPaint::kMiter_Join); |
- const bool isBevel = (join == SkPaint::kBevel_Join); |
- SkScalar invMiterLimit = isMiter ? SK_Scalar1 / miterLimit : 0; |
- SkScalar invMiterLimitSq = SkScalarMul(invMiterLimit, invMiterLimit); |
- |
- // Allocate vertices |
- const int nbQuads = origPath.countPoints() + 1; // Could be "-1" if path is not closed |
- const int extraVerts = isMiter || isBevel ? 1 : 0; |
- const int maxVertexCount = nbQuads * (4 + extraVerts); |
- const int maxIndexCount = nbQuads * (6 + extraVerts * 3); // Each extra vert adds a triangle |
- target->drawState()->setDefaultVertexAttribs(); |
- GrDrawTarget::AutoReleaseGeometry arg(target, maxVertexCount, maxIndexCount); |
- if (!arg.succeeded()) { |
- return false; |
- } |
- SkPoint* verts = reinterpret_cast<SkPoint*>(arg.vertices()); |
- uint16_t* idxs = reinterpret_cast<uint16_t*>(arg.indices()); |
- int vCount = 0, iCount = 0; |
- |
- // Transform the path into a list of triangles |
- SkPath::Iter iter(origPath, false); |
- SkPoint pts[4]; |
- const SkScalar radius = SkScalarMul(width, 0.5f); |
- SkPoint *firstPt = verts, *lastPt = NULL; |
- SkVector firstDir, dir; |
- firstDir.set(0, 0); |
- dir.set(0, 0); |
- bool isOpen = true; |
- for(SkPath::Verb v = iter.next(pts); v != SkPath::kDone_Verb; v = iter.next(pts)) { |
- switch(v) { |
- case SkPath::kMove_Verb: |
- // This will already be handled as pts[0] of the 1st line |
- break; |
- case SkPath::kClose_Verb: |
- isOpen = (lastPt == NULL); |
- break; |
- case SkPath::kLine_Verb: |
- { |
- SkVector v0 = dir; |
- dir = pts[1] - pts[0]; |
- if (dir.setLength(radius)) { |
- SkVector dirT; |
- dirT.set(dir.fY, -dir.fX); // Get perpendicular direction |
- SkPoint l1a = pts[0]+dirT, l1b = pts[1]+dirT, |
- l2a = pts[0]-dirT, l2b = pts[1]-dirT; |
- SkPoint miterPt[2]; |
- bool useMiterPoint = false; |
- int idx0(-1), idx1(-1); |
- if (NULL == lastPt) { |
- firstDir = dir; |
- } else { |
- SkVector v1 = dir; |
- if (v0.normalize() && v1.normalize()) { |
- SkScalar dotProd = v0.dot(v1); |
- // No need for bevel or miter join if the angle |
- // is either 0 or 180 degrees |
- if (!SkScalarNearlyZero(dotProd + SK_Scalar1) && |
- !SkScalarNearlyZero(dotProd - SK_Scalar1)) { |
- bool ccw = !is_clockwise(v0, v1); |
- int offset = ccw ? 1 : 0; |
- idx0 = vCount-2+offset; |
- idx1 = vCount+offset; |
- const SkPoint* pt0 = &(lastPt[offset]); |
- const SkPoint* pt1 = ccw ? &l2a : &l1a; |
- switch(join) { |
- case SkPaint::kMiter_Join: |
- { |
- // *Note : Logic is from MiterJoiner |
- |
- // FIXME : Special case if we have a right angle ? |
- // if (SkScalarNearlyZero(dotProd)) {...} |
- |
- SkScalar sinHalfAngleSq = |
- SkScalarHalf(SK_Scalar1 + dotProd); |
- if (sinHalfAngleSq >= invMiterLimitSq) { |
- // Find the miter point (or points if it is further |
- // than the miter limit) |
- const SkPoint pt2 = *pt0+v0, pt3 = *pt1+v1; |
- if (intersection(*pt0, pt2, *pt1, pt3, miterPt[0]) != |
- kNone_IntersectionType) { |
- SkPoint miterPt0 = miterPt[0] - *pt0; |
- SkPoint miterPt1 = miterPt[0] - *pt1; |
- SkScalar sqDist0 = miterPt0.dot(miterPt0); |
- SkScalar sqDist1 = miterPt1.dot(miterPt1); |
- const SkScalar rSq = radius*radius / sinHalfAngleSq; |
- const SkScalar sqRLimit = |
- SkScalarMul(sqMiterLimit, rSq); |
- if (sqDist0 > sqRLimit || sqDist1 > sqRLimit) { |
- if (sqDist1 > sqRLimit) { |
- v1.setLength(SkScalarSqrt(sqRLimit)); |
- miterPt[1] = *pt1+v1; |
- } else { |
- miterPt[1] = miterPt[0]; |
- } |
- if (sqDist0 > sqRLimit) { |
- v0.setLength(SkScalarSqrt(sqRLimit)); |
- miterPt[0] = *pt0+v0; |
- } |
- } else { |
- miterPt[1] = miterPt[0]; |
- } |
- useMiterPoint = true; |
- } |
- } |
- if (useMiterPoint && (miterPt[1] == miterPt[0])) { |
- break; |
- } |
- } |
- default: |
- case SkPaint::kBevel_Join: |
- { |
- // Note : This currently causes some overdraw where both |
- // lines initially intersect. We'd need to add |
- // another line intersection check here if the |
- // overdraw becomes an issue instead of using the |
- // current point directly. |
- |
- // Add center point |
- *verts++ = pts[0]; // Use current point directly |
- // This idx is passed the current point so increment it |
- ++idx1; |
- // Add center triangle |
- *idxs++ = idx0; |
- *idxs++ = vCount; |
- *idxs++ = idx1; |
- vCount++; |
- iCount += 3; |
- } |
- break; |
- } |
- } |
- } |
- } |
- *verts++ = l1a; |
- *verts++ = l2a; |
- lastPt = verts; |
- *verts++ = l1b; |
- *verts++ = l2b; |
- |
- if (useMiterPoint && (idx0 >= 0) && (idx1 >= 0)) { |
- firstPt[idx0] = miterPt[0]; |
- firstPt[idx1] = miterPt[1]; |
- } |
- |
- // 1st triangle |
- *idxs++ = vCount+0; |
- *idxs++ = vCount+2; |
- *idxs++ = vCount+1; |
- // 2nd triangle |
- *idxs++ = vCount+1; |
- *idxs++ = vCount+2; |
- *idxs++ = vCount+3; |
- |
- vCount += 4; |
- iCount += 6; |
- } |
- } |
- break; |
- case SkPath::kQuad_Verb: |
- case SkPath::kCubic_Verb: |
- SkDEBUGFAIL("Curves not supported!"); |
- default: |
- // Unhandled cases |
- SkASSERT(false); |
- } |
- } |
- |
- if (isOpen) { |
- // Add caps |
- switch (stroke.getCap()) { |
- case SkPaint::kSquare_Cap: |
- firstPt[0] -= firstDir; |
- firstPt[1] -= firstDir; |
- lastPt [0] += dir; |
- lastPt [1] += dir; |
- break; |
- case SkPaint::kRound_Cap: |
- SkDEBUGFAIL("Round caps not supported!"); |
- default: // No cap |
- break; |
- } |
- } |
- |
- SkASSERT(vCount <= maxVertexCount); |
- SkASSERT(iCount <= maxIndexCount); |
- |
- if (vCount > 0) { |
- target->drawIndexed(kTriangles_GrPrimitiveType, |
- 0, // start vertex |
- 0, // start index |
- vCount, |
- iCount); |
- } |
- |
- return true; |
-} |