aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEirik Aavitsland <[email protected]>2023-11-30 09:58:28 +0100
committerEirik Aavitsland <[email protected]>2023-12-08 08:35:35 +0100
commitfa353f1c7d885c80dc70d3e7e0e1bc0a88794428 (patch)
tree405fd99156f2101ac24a60937c91d42de1f1def1
parent27c98f5a9a3047b7e33c1873d5fb23e7098e9661 (diff)
Curve renderer: drop the control point magic for line elements
Now that we are adding ever more manipulations of quadpaths, relying on this silent state to not having been lost on the way is bugprone. Also, being instead able to rely on the control point of a line always being the line's midpoint, so that the element is a valid representation even if treated as quad curve, makes for more resilient code: it can make it optional whether to treat lines specially. So replace the magic value by a new Element method referencePoint(), that returns the control point for curves and the inside point for lines, and use that in the one place that used to rely on the special line control point. Change-Id: Id54b9034d23d7bc7794f2f77fab36fbfe137a60e Reviewed-by: Paul Olav Tvete <[email protected]>
-rw-r--r--src/quick/scenegraph/qsgcurveprocessor.cpp12
-rw-r--r--src/quick/scenegraph/util/qquadpath.cpp9
-rw-r--r--src/quick/scenegraph/util/qquadpath_p.h14
3 files changed, 24 insertions, 11 deletions
diff --git a/src/quick/scenegraph/qsgcurveprocessor.cpp b/src/quick/scenegraph/qsgcurveprocessor.cpp
index 805cdf3a46..427a344413 100644
--- a/src/quick/scenegraph/qsgcurveprocessor.cpp
+++ b/src/quick/scenegraph/qsgcurveprocessor.cpp
@@ -35,7 +35,7 @@ static inline QVector2D curveUv(QVector2D p0, QVector2D p1, QVector2D p2, QVecto
static QVector3D elementUvForPoint(const QQuadPath::Element& e, QVector2D p)
{
- auto uv = curveUv(e.startPoint(), e.controlPoint(), e.endPoint(), p);
+ auto uv = curveUv(e.startPoint(), e.referencePoint(), e.endPoint(), p);
if (e.isLine())
return { uv.x(), uv.y(), 0.0f };
else
@@ -179,6 +179,7 @@ static bool isOverlap(const QQuadPath &path, int e1, int e2)
const QQuadPath::Element &element1 = path.elementAt(e1);
const QQuadPath::Element &element2 = path.elementAt(e2);
+ Q_ASSERT(!element1.isLine());
TrianglePoints t1{ element1.startPoint(), element1.controlPoint(), element1.endPoint() };
if (element2.isLine()) {
@@ -195,6 +196,7 @@ static bool isOverlap(const QQuadPath &path, int e1, int e2)
static bool isOverlap(const QQuadPath &path, int index, const QVector2D &vertex)
{
const QQuadPath::Element &elem = path.elementAt(index);
+ Q_ASSERT(!elem.isLine());
return checkTriangleContains(vertex, elem.startPoint(), elem.controlPoint(), elem.endPoint());
}
@@ -308,6 +310,7 @@ QList<TriangleData> simplePointTriangulator(const QList<QVector2D> &pts, const Q
static bool needsSplit(const QQuadPath::Element &el)
{
+ Q_ASSERT(!el.isLine());
const auto v1 = el.controlPoint() - el.startPoint();
const auto v2 = el.endPoint() - el.controlPoint();
float cos = QVector2D::dotProduct(v1, v2) / (v1.length() * v2.length());
@@ -454,13 +457,14 @@ static QList<TriangleData> customTriangulator2(const QQuadPath &path, float penW
const QVector2D &n1, const QVector2D &n2, const QVector2D &n3, const QVector2D &n4)
{
const auto &element = path.elementAt(idx);
+ Q_ASSERT(!element.isLine());
const auto &s = element.startPoint();
const auto &c = element.controlPoint();
const auto &e = element.endPoint();
// TODO: Don't flatten the path in addCurveStrokeNodes, but iterate over the children here instead
bool controlPointOnRight = determinant(s, c, e) > 0;
- QVector2D startNormal = normalVector(element).normalized();
- QVector2D endNormal = normalVector(element, true).normalized();
+ QVector2D startNormal = normalVector(element);
+ QVector2D endNormal = normalVector(element, true);
QVector2D controlPointNormal = (startNormal + endNormal).normalized();
if (controlPointOnRight)
controlPointNormal = -controlPointNormal;
@@ -786,7 +790,7 @@ void QSGCurveProcessor::processStroke(const QQuadPath &strokePath,
auto thePath = subdivide(strokePath, subdivisions).flattened(); // TODO: don't flatten, but handle it in the triangulator
auto triangles = customTriangulator2(thePath, penWidth, joinStyle, capStyle, miterLimit);
- auto addCurveTriangle = [&](const QQuadPath::Element &element, const TriangleData &t){
+ auto addCurveTriangle = [&](const QQuadPath::Element &element, const TriangleData &t) {
addTriangle(t.points,
{ element.startPoint(), element.controlPoint(), element.endPoint() },
t.normals,
diff --git a/src/quick/scenegraph/util/qquadpath.cpp b/src/quick/scenegraph/util/qquadpath.cpp
index c78c650db9..8ce818ae1f 100644
--- a/src/quick/scenegraph/util/qquadpath.cpp
+++ b/src/quick/scenegraph/util/qquadpath.cpp
@@ -219,6 +219,8 @@ float QQuadPath::Element::extent() const
// The t values of max 2 intersection(s) are stored in the fractions array
int QQuadPath::Element::intersectionsAtY(float y, float *fractions) const
{
+ Q_ASSERT(!isLine());
+
const float y0 = startPoint().y() - y;
const float y1 = controlPoint().y() - y;
const float y2 = endPoint().y() - y;
@@ -436,13 +438,6 @@ void QQuadPath::addCurvatureData()
if (element.isLine()) {
element.m_curvatureFlags = flags;
- // Set the control point to an arbitrary point on the inside side of the line
- // (doesn't need to actually be inside the shape: it just makes our calculations
- // easier later if it is at the same side as the fill).
- const QVector2D &sp = element.sp;
- const QVector2D &ep = element.ep;
- QVector2D v = ep - sp;
- element.cp = flags & Element::FillOnRight ? sp + QVector2D(-v.y(), v.x()) : sp + QVector2D(v.y(), -v.x());
} else {
bool controlPointOnLeft = element.isControlPointOnLeft();
bool isFillOnRight = flags & Element::FillOnRight;
diff --git a/src/quick/scenegraph/util/qquadpath_p.h b/src/quick/scenegraph/util/qquadpath_p.h
index 74589e3ab9..d1d8f32eb1 100644
--- a/src/quick/scenegraph/util/qquadpath_p.h
+++ b/src/quick/scenegraph/util/qquadpath_p.h
@@ -75,6 +75,20 @@ public:
return isLine() ? 0.5f * (sp + ep) : (0.25f * sp) + (0.5f * cp) + (0.25 * ep);
}
+ /* For a curve, returns the control point. For a line, returns an arbitrary point on the
+ * inside side of the line (assuming the curvature has been set for the path). The point
+ * doesn't need to actually be inside the shape: it just makes for easier calculations
+ * later when it is at the same side as the fill. */
+ QVector2D referencePoint() const
+ {
+ if (isLine()) {
+ QVector2D normal(sp.y() - ep.y(), ep.x() - sp.x());
+ return m_curvatureFlags & Element::FillOnRight ? sp + normal : sp - normal;
+ } else {
+ return cp;
+ }
+ }
+
int childCount() const { return m_numChildren; }
int indexOfChild(int childNumber) const