diff options
author | Eirik Aavitsland <[email protected]> | 2023-11-30 09:58:28 +0100 |
---|---|---|
committer | Eirik Aavitsland <[email protected]> | 2023-12-08 08:35:35 +0100 |
commit | fa353f1c7d885c80dc70d3e7e0e1bc0a88794428 (patch) | |
tree | 405fd99156f2101ac24a60937c91d42de1f1def1 | |
parent | 27c98f5a9a3047b7e33c1873d5fb23e7098e9661 (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.cpp | 12 | ||||
-rw-r--r-- | src/quick/scenegraph/util/qquadpath.cpp | 9 | ||||
-rw-r--r-- | src/quick/scenegraph/util/qquadpath_p.h | 14 |
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 |