[GPU]: Handle degenerate quads when computing UV matrix from control points
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 31 Jan 2012 20:46:32 +0000 (20:46 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 31 Jan 2012 20:46:32 +0000 (20:46 +0000)
Review URL: http://codereview.appspot.com/5602045/

git-svn-id: http://skia.googlecode.com/svn/trunk@3125 2bbb7eff-a529-9590-31e7-b0007b416f81

gm/convexpaths.cpp
src/gpu/GrPathUtils.cpp

index c72af07..d4f2e7f 100644 (file)
@@ -97,6 +97,13 @@ protected:
                                     20 * SK_Scalar1, 100 * SK_Scalar1,
                                      0 * SK_Scalar1,   0 * SK_Scalar1);
 
+        // triangle where one edge is a degenerate quad
+        fPaths.push_back().moveTo(SkFloatToScalar(8.59375f), 45 * SK_Scalar1);
+        fPaths.back().quadTo(SkFloatToScalar(16.9921875f),   45 * SK_Scalar1,
+                             SkFloatToScalar(31.25f),        45 * SK_Scalar1);
+        fPaths.back().lineTo(100 * SK_Scalar1,              100 * SK_Scalar1);
+        fPaths.back().lineTo(SkFloatToScalar(8.59375f),      45 * SK_Scalar1);
+
         // point degenerate
         fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
         fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
@@ -108,6 +115,7 @@ protected:
         fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
                               50 * SK_Scalar1, 50 * SK_Scalar1,
                               50 * SK_Scalar1, 50 * SK_Scalar1);
+
         // moveTo only paths
         fPaths.push_back().moveTo(0, 0);
         fPaths.back().moveTo(0, 0);
index 349b887..2951e1f 100644 (file)
@@ -225,16 +225,52 @@ void GrPathUtils::quadDesignSpaceToUVCoordsMatrix(const SkPoint qPts[3],
 #ifndef SK_SCALAR_IS_FLOAT
     GrCrash("Expected scalar is float.");
 #endif
-    
+    // We want M such that M * xy_pt = uv_pt
+    // We know M * control_pts = [0  1/2 1]
+    //                           [0  0   1]
+    //                           [1  1   1]
+    // We invert the control pt matrix and post concat to both sides to get M.
     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);
+    if (!matrix->invert(matrix)) {
+        // The quad is degenerate. Hopefully this is rare. Find the pts that are
+        // farthest apart to compute a line (unless it is really a pt).
+        SkScalar maxD = qPts[0].distanceToSqd(qPts[1]);
+        int maxEdge = 0;
+        SkScalar d = qPts[1].distanceToSqd(qPts[2]);
+        if (d > maxD) {
+            maxD = d;
+            maxEdge = 1;
+        }
+        d = qPts[2].distanceToSqd(qPts[0]);
+        if (d > maxD) {
+            maxD = d;
+            maxEdge = 2;
+        }
+        // We could have a tolerance here, not sure if it would improve anything
+        if (maxD > 0) {
+            // Set the matrix to give (u = 0, v = distance_to_line)
+            GrVec lineVec = qPts[maxEdge] - qPts[(maxEdge + 1)%3];
+            lineVec.setOrthog(lineVec);
+            lineVec.dot(qPts[0]);
+            matrix->setAll(0, 0, 0,
+                           lineVec.fX, lineVec.fY, -lineVec.dot(qPts[maxEdge]),
+                           0, 0, 1.f);
+        } else {
+            // It's a point. It should cover zero area. Just set the matrix such
+            // that (u, v) will always be far away from the quad.
+            matrix->setAll(0, 0, 100 * SK_Scalar1,
+                           0, 0, 100 * SK_Scalar1,
+                           0, 0, 1.f);
+        }
+    } else {
+        matrix->postConcat(UVpts);
+        fixup_matrix(matrix);
+    }
 }
 
 namespace {