aboutsummaryrefslogtreecommitdiffhomepage
path: root/gpu/src/GrPathUtils.cpp
diff options
context:
space:
mode:
authorGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-03-28 20:47:09 +0000
committerGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-03-28 20:47:09 +0000
commit9d18b7873ce9b44f130a41e0cbd0a3df76ab9adf (patch)
tree5f5f96e33ea96bdaf6c0dc4fbb32f78db26a4642 /gpu/src/GrPathUtils.cpp
parentcae5fba82e687d674b076b10cdc8aba46e1ac3b3 (diff)
This CL implements a tesselated path renderer, using GLU's libtess. All of the
fill modes except hairline are supported. Note that the path renderer is not enabled by default; to enable it, replace "GrCreatePathRenderer_none.cpp" with "GrCreatePathRenderer_tesselated.cpp" in skia.gyp, and run gyp_skia, and build. This change also contains a number of build fixes for Win32 (for building SampleApp on VS2008) and Mac (for my ancient Mac Pro which supports GL_EXT_framebuffer_object but not GL_ARB_framebuffer_object). Also, priorityq-heap.c was removed from the SampleApp build, since it's #included by priorityq.c (weird, I know). NB: When this change is rolled into chrome, some modifications to chromium's skia.gyp will be necessary. Review URL: http://codereview.appspot.com/4289072/ git-svn-id: http://skia.googlecode.com/svn/trunk@1012 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'gpu/src/GrPathUtils.cpp')
-rw-r--r--gpu/src/GrPathUtils.cpp144
1 files changed, 144 insertions, 0 deletions
diff --git a/gpu/src/GrPathUtils.cpp b/gpu/src/GrPathUtils.cpp
new file mode 100644
index 0000000000..274dc49a57
--- /dev/null
+++ b/gpu/src/GrPathUtils.cpp
@@ -0,0 +1,144 @@
+/*
+ Copyright 2011 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include "GrPathUtils.h"
+
+#include "GrPathIter.h"
+#include "GrPoint.h"
+
+const GrScalar GrPathUtils::gTolerance = GR_Scalar1;
+
+static const uint32_t MAX_POINTS_PER_CURVE = 1 << 10;
+
+uint32_t GrPathUtils::quadraticPointCount(const GrPoint points[],
+ GrScalar tol) {
+ GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
+ if (d < tol) {
+ return 1;
+ } else {
+ // Each time we subdivide, d should be cut in 4. So we need to
+ // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
+ // points.
+ // 2^(log4(x)) = sqrt(x);
+ d = ceilf(sqrtf(d/tol));
+ return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
+ }
+}
+
+uint32_t GrPathUtils::generateQuadraticPoints(const GrPoint& p0,
+ const GrPoint& p1,
+ const GrPoint& p2,
+ GrScalar tolSqd,
+ GrPoint** points,
+ uint32_t pointsLeft) {
+ if (pointsLeft < 2 ||
+ (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
+ (*points)[0] = p2;
+ *points += 1;
+ return 1;
+ }
+
+ GrPoint q[] = {
+ GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
+ GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
+ };
+ GrPoint r(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY));
+
+ pointsLeft >>= 1;
+ uint32_t a = generateQuadraticPoints(p0, q[0], r, tolSqd, points, pointsLeft);
+ uint32_t b = generateQuadraticPoints(r, q[1], p2, tolSqd, points, pointsLeft);
+ return a + b;
+}
+
+uint32_t GrPathUtils::cubicPointCount(const GrPoint points[],
+ GrScalar tol) {
+ GrScalar d = GrMax(points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
+ points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
+ d = sqrtf(d);
+ if (d < tol) {
+ return 1;
+ } else {
+ d = ceilf(sqrtf(d/tol));
+ return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
+ }
+}
+
+uint32_t GrPathUtils::generateCubicPoints(const GrPoint& p0,
+ const GrPoint& p1,
+ const GrPoint& p2,
+ const GrPoint& p3,
+ GrScalar tolSqd,
+ GrPoint** points,
+ uint32_t pointsLeft) {
+ if (pointsLeft < 2 ||
+ (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
+ p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
+ (*points)[0] = p3;
+ *points += 1;
+ return 1;
+ }
+ GrPoint q[] = {
+ GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
+ GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
+ GrPoint(GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY))
+ };
+ GrPoint r[] = {
+ GrPoint(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)),
+ GrPoint(GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY))
+ };
+ GrPoint s(GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY));
+ pointsLeft >>= 1;
+ uint32_t a = generateCubicPoints(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
+ uint32_t b = generateCubicPoints(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
+ return a + b;
+}
+
+int GrPathUtils::worstCasePointCount(GrPathIter* path,
+ int* subpaths,
+ GrScalar tol) {
+ int pointCount = 0;
+ *subpaths = 1;
+
+ bool first = true;
+
+ GrPathCmd cmd;
+
+ GrPoint pts[4];
+ while ((cmd = path->next(pts)) != kEnd_PathCmd) {
+
+ switch (cmd) {
+ case kLine_PathCmd:
+ pointCount += 1;
+ break;
+ case kQuadratic_PathCmd:
+ pointCount += quadraticPointCount(pts, tol);
+ break;
+ case kCubic_PathCmd:
+ pointCount += cubicPointCount(pts, tol);
+ break;
+ case kMove_PathCmd:
+ pointCount += 1;
+ if (!first) {
+ ++(*subpaths);
+ }
+ break;
+ default:
+ break;
+ }
+ first = false;
+ }
+ return pointCount;
+}