Add conic fill support to the tessellator
This started out as a sandbox to experiment with a Wang's formula
analog for rational quadratics, but it quickly became apparent that
running Wang's formula on the down-projected points was an upper bound
on what the rational version would have been (for both w<1 and w>1).
This CL therefore adds conic support by upgrading the tessellation
shaders to use ratoinal cubics, converting every path verb to a
rational cubic, and then running Wang's formula on the down-projected
points. In the future we can always drop in a better formula if we
work one out.
Bug: skia:10419
Change-Id: I97021ea56afea54fdbe76745bacd3251e350fd97
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/337156
Reviewed-by: Tyler Denniston <tdenniston@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/samplecode/SampleTessellatedWedge.cpp b/samplecode/SampleTessellatedWedge.cpp
index 929489c..6465d75 100644
--- a/samplecode/SampleTessellatedWedge.cpp
+++ b/samplecode/SampleTessellatedWedge.cpp
@@ -20,6 +20,8 @@
#include "src/gpu/GrRenderTargetContextPriv.h"
#include "src/gpu/tessellate/GrPathTessellateOp.h"
+static float kConicWeight = .5;
+
// This sample enables wireframe and visualizes the triangulation generated by
// GrTessellateWedgeShader.
class TessellatedWedge : public Sample {
@@ -35,9 +37,9 @@
fPath.transform(SkMatrix::Scale(200, 200));
fPath.transform(SkMatrix::Translate(300, 300));
#else
- fPath.moveTo(100, 200);
- fPath.cubicTo(100, 100, 400, 100, 400, 200);
- fPath.lineTo(250, 500);
+ fPath.moveTo(100, 300);
+ fPath.conicTo(300, 100, 500, 300, kConicWeight);
+ fPath.cubicTo(433, 366, 366, 433, 300, 500);
#endif
}
@@ -107,6 +109,14 @@
}
fLastViewMatrix = canvas->getTotalMatrix();
+
+
+ SkString caption;
+ caption.printf("w=%f (=/- and +/_ to change)", kConicWeight);
+ SkFont font(nullptr, 20);
+ SkPaint captionPaint;
+ captionPaint.setColor(SK_ColorWHITE);
+ canvas->drawString(caption, 10, 30, font, captionPaint);
}
class TessellatedWedge::Click : public Sample::Click {
@@ -145,6 +155,32 @@
return true;
}
+static SkPath update_weight(const SkPath& path) {
+ SkPath path_;
+ for (auto [verb, pts, _] : SkPathPriv::Iterate(path)) {
+ switch (verb) {
+ case SkPathVerb::kMove:
+ path_.moveTo(pts[0]);
+ break;
+ case SkPathVerb::kLine:
+ path_.lineTo(pts[1]);
+ break;
+ case SkPathVerb::kQuad:
+ path_.quadTo(pts[1], pts[2]);
+ break;
+ case SkPathVerb::kCubic:
+ path_.cubicTo(pts[1], pts[2], pts[3]);
+ break;
+ case SkPathVerb::kConic:
+ path_.conicTo(pts[1], pts[2], (kConicWeight != 1) ? kConicWeight : .99f);
+ break;
+ default:
+ SkUNREACHABLE;
+ }
+ }
+ return path_;
+}
+
bool TessellatedWedge::onChar(SkUnichar unichar) {
switch (unichar) {
case 'w':
@@ -155,6 +191,22 @@
fPath.dump();
return true;
}
+ case '+':
+ kConicWeight *= 2;
+ fPath = update_weight(fPath);
+ return true;
+ case '=':
+ kConicWeight *= 5/4.f;
+ fPath = update_weight(fPath);
+ return true;
+ case '_':
+ kConicWeight *= .5f;
+ fPath = update_weight(fPath);
+ return true;
+ case '-':
+ kConicWeight *= 4/5.f;
+ fPath = update_weight(fPath);
+ return true;
}
return false;
}