| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
QSvgRenderer already obeys the QPen::isCosmetic() setting.
Now we add a ShapePath.cosmeticStroke property and try to support
cosmetic stroking both with SVG and with Shapes, in all renderers.
The curve renderer now starts with skinny triangles: each segment's end
vertices are passed to the vertex shader with their original positions,
and the shader uses the normal and the stroke width to expand the stroke
triangles outwards as needed. We always add triangles for end caps,
regardless whether they are square or round. We get rid of
addBevelTriangle and fix bevels, square caps and miters:
All three of these cases are done by drawing lines adjusted to the
right direction within the respective triangles. And to avoid seeing
rounded ends at any reasonable zoom level, we need the line equation
coefficients to take the line very far outside the actual triangles.
Square caps are really square: we render line segments in those three
triangles, not extensions of the adjacent curve or line.
Miters are also rendered as straight tangent lines.
The bevel's triangle is very short when the join is an acute angle,
and almost as tall as the full stroke width when the join is very
obtuse. But when the triangle is short, we need to diminish the stroke
width rendered in the fragment shader so that the center of the stroke
falls on the inner corner of that triangle, and the edge of the stroke
is rendered along the outer bevel edge rather than trying to go outside.
That's achieved by multiplying the stroke width by the cosine of half
the total angle, AKA the dot product. That is now in the normalExt.z
vertex attribute.
Normals (normalExt.xy) can be premultiplied rather than normalized:
in fact some of them already have length > 1.
In qsgbatchrenderer, Renderer::prepareAlphaBatches() breaks batches
when overlaps occur. Now that we stroke lines with vertices that
represent them as zero-width lines (and thus Element.bounds has
the same x or y coordinates on both corners), we must consider lines
right on top of each other to be overlapping: e.g. the stacks of
horizontal (dashed) line segments in paint-stroke-202-t.svg must be
in separate batches.
At the time QQuickShape::updatePaintNode() is called, the available
transform node (from UpdatePaintNodeData or an individual node's parent
which is a transform node) does not contain the scaling factor that we
need to allow for the stroke width to be adjusted for cosmetic stroking.
But in QQuickShapePrivate::sync(), windowToItemTransform() is known, and
from bde55ad574ac84440e2cdc9c1122a344bb1cb67a we have a precedent in
QSGCurveStrokeMaterialShader::updateUniformData() for using the square
root of the matrix determinant as a scaling approximation (ok when the
scaling is uniform). QQuickShapeSoftwareRenderer::setNode() was already
adjusting a path's bounding rect by its stroke width, and we need a
multiplicative factor there to account for cosmetic stroking, to avoid
excessive clipping in the software renderer. So now we have another use
for the triangulationScale that was introduced in
bcfcaeb87be783d8c329b0bc96323f1c9863982d.
When QQShapeGenericRenderer is used (rendererType == GeometryRenderer),
and any ShapePath has cosmeticStroke, we need it to re-triangulate
whenever scale changes. QQuickShapeGenericRenderer::triangulateStroke()
calls QTriangulatingStroker::setInvScale(1 / triangulationScale), and
QTriangulatingStroker::process() multiplies its m_width by the inverse
scale that was set (since 2009). So this tells us that the intended
meaning of triangulationScale is the inverse of the factor by which we
multiply the pen width. And when QQShapeGenericRenderer is in use,
and there are cosmetic strokes, QQuickShape::itemChange triggers
re-triangulation on changes in scale.
When setting the QQuickShapeCurveRenderer::DebugWireframe debug
visualization flag, we need to repeat the vertex shader calculations to
expand the "skinny" triangles according to stroke width, just as we do
with the actual stroking vertices.
For now customTriangulator2 remains as legacy code, to be removed later
on. It's poorly named, and returns a list of TriangleData which need to
be iterated afterwards ("fix it in post"), looking up the
QQuadPath::Element again in that second loop, which can go wrong when a
path contains a move command. (For example, it could calculate a bevel
between the end-tangent of one subpath and the start-tangent of the
next.) customTriangulator2() was called from only one place,
processStroke(), to which addStrokeTriangleCallback() is given: so the
new way is to just call the callback directly as soon as we've
calculated each triangle. Because we are not iterating again afterwards,
the switch(type) is not needed in that case, and we no longer need
TriangleData::type, except for supporting customTriangulator2().
[ChangeLog][QtQuick][Shapes] ShapePath now has a cosmeticStroke
property which causes strokeWidth to be constant despite scaling.
Set the environment variable QT_QUICKSHAPES_STROKE_EXPANDING to 1 to
enable an experimental method of expanding strokes in the vertex shader,
minimizing the need to re-triangulate when strokeWidth changes.
Task-number: QTBUG-124638
Change-Id: I4eac0ddcd6f623b79bc70c766ff116f4b77736cb
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
| |
|
|
|
|
|
|
| |
Also ifndef QT_NO_DEBUG_STREAM around the QQuadPath debug op.
Both will be omitted from the build if QT_NO_DEBUG_STREAM is set.
Change-Id: Ie86577ba61fc4f2b118d7e0a2b1ab702b318a473
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- calculateJoin() is too big to continue as an internal lambda, and
changes to customTriangulator2 (the only user) are coming later;
so move it out to a top-level static function
- use const
- capture simple constants in the tooLong lambda
- explicit captures in remaining lambdas
- replace some single-letter variables with more meaningful ones
- turn some plain comments into internal function docs
- a couple of spelling and grammar corrections
- init TriangleData::pathElementIndex=INT_MIN by default,
to be able to distinguish default-constructed instances.
Of course they are usually >= 0, but customTriangulator2() uses
small negative indices as special triangle-type indicators.
Change-Id: I7b70a02ac56522ee0c6aff26be80ac4e3e546bbd
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
| |
|
|
|
|
|
|
| |
QPair is just an alias of std::pair anyway.
Task-number: QTBUG-115841
Change-Id: I26fc90adcc775aac9955ad57304af914dc4ed48f
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
| |
|
|
|
|
|
|
|
|
| |
Change the C-style array to std::array. Initializing C-style arrays from
temporaries seems suspicious. This issue was flagged by Clang-Tidy as a
warning.
Pick-to: 6.9 6.8
Change-Id: I7f9e5aefcda802ee0b45b39634175a634976b4a9
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
| |
|
|
|
|
|
|
| |
We will soon need more flags to deal with cosmetic stroking.
Passing a bool was predictably limiting.
Change-Id: I3f1a2e27b4cb75fd3b974e4f24604c5284809251
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
| |
|
|
|
|
|
|
|
| |
Minor code improvements, mostly removing unnecessary code.
Task-number: QTBUG-127121
Pick-to: 6.8
Change-Id: I57732969c06c441c3e1296dc7618e50f279e5bd1
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Either make them static or declare them in a header. We want them to be
static wherever possible, in order to reduce the number of visible
symbols. If they can't be static, however, they should at least be
declared in only one place.
Task-number: QTBUG-67692
Change-Id: I485bb7e4379e86f72619f848399ad58c76586851
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
At ordinary intersections we use the intersection angle to decide on the
next step forward. This does not work for intersections at the start and
end points and we are falling back to finding inside/outside
numerically. However, this was only done for one of the segments,
leading to rendering bugs if it happened on the other segment. This
patch also applies the numerical method to the second segment.
Pick-to: 6.7
Fixes: QTBUG-125864
Change-Id: I490acb74ea6215efa1986c7c6bfbcdd8c3172120
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
| |
Avoiding repeated calculations, allocations etc. No behavior change.
Also replace the remaining qWarnings ("this should not happen") with
qCDebugs(), since they are not intended for users.
Pick-to: 6.7
Change-Id: I917fc61cba7281d68c9a8c22622a70f2003adf6f
Reviewed-by: Matthias Rauter <matthias.rauter@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
For code simplification, replace a couple of ad-hoc QQuadPath
iteration implementations with calls to QQuadPath's own
iterateElements() function.
To make that possible, extend iterateElements() to pass the element
index too to the lambda function.
Pick-to: 6.7
Change-Id: I2e6697b5d1404c7ed4fa1c247e18f93856394fa1
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In addFillNodes():
- Pre-allocate estimated needed number of elements in temporary lists,
to avoid reallocations.
In processFill():
- Remove QHashes that were never read
- Fewer conversions QVector2D<->QPointF (float<->double)
- Add a qHash for QVector2D. Simplifies by removing need for
conversion to qpair<float, float>, and is also more efficient since
it hashes both elements at once.
Pick-to: 6.7
Change-Id: If11c67ee198d9d29a9d290efe0e808fb7c70ee9c
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
| |
|
|
|
|
|
|
|
|
| |
We would take a reference to the element and then modify
the path, which would cause us to read uninitialized memory
and later assert.
Pick-to: 6.7
Change-Id: Ib8f3e289dea44fdd6f51649de776b7fba63c62d9
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Nested paths that were neither generating a new hole or a new filling
resulted in double filling of some areas. The previous workaround
was to force the intersectionSolver to generate a new path, however,
which is computational expensive and does not allow to check for
changes.
This patch introduces a dedicated function to remove superfluos
nested subpaths. It should be faster than the previous solution and
allows to track changes to the path.
With this patch, the intersectionSolver returns true only if the path
was changed.
Pick-to: 6.7
Change-Id: I16919f20b4e5460ddd729e8be7703fb2879c3190
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
|
| |
|
|
|
|
|
|
| |
This also removes the warning that no valid starting point was found.
Pick-to: 6.7
Change-Id: I7cc46bd0bfb57b869f3bc2e80ecba3e6d6ae1bc7
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
When we hit an intersection, we use the angle between the segments to
decide in which direction to continue. This concept falls apart when we
intersect a path at the join between two segments. For this case we have
to fall back to check the fill side. This is more expensive and thus not
done for every intersection.
Pick-to: 6.7
Change-Id: Iebefc84fe3d299e5c31817ba34b3a1cdcb1e7d68
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
| |
In order to fix the example, the isOverlap() function had to be removed
from the findOverlapCandidates() function.
The example that triggered the bug is added to the baseline testsuit.
Pick-to: 6.7
Change-Id: Ibcbf7d1200a284917f6ad87114df29eafbe6aa5b
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
|
| |
|
|
|
|
|
|
|
|
| |
If the path has no intersections to start with, then solveIntersections
will return the path unchanged. Set the PathNonIntersecting optimization
flag in that case.
Pick-to: 6.7
Change-Id: I6f560c97c8722b2940d69acc0c6cfd545f86e7f2
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
| |
|
|
|
|
|
|
|
|
| |
For a single triangle inner hull, qTriangulate() will sometimes give
an unexpected result in the index list. Fix by overwriting it with the
expected result, since that is static and known for this simple case.
Pick-to: 6.7
Change-Id: I76d697f85f233b0c2ecc50da3074def89e860697
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Use QSGCurveProcessor::findOverlappingCandidates() to reduce
the complexity from O(n^2) to O(n log n). The new code now
supports the concave join case by default.
This means that the QT_QUICKSHAPES_WIP_CONCAVE_JOINT
environment variable no longer serves a purpose, so
it is removed.
Task-number: QTBUG-121215
Fixes: QTBUG-114807
Pick-to: 6.7
Change-Id: I080ef08cb5c7e581abfbb1e66d47bdd48f3019c5
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Add --optimize-paths option to do expensive path manipulation
at build time instead of at runtime. This may cause the generation
of separate fill and stroke versions of the same source path.
Task-number: QTBUG-116883
Task-number: QTBUG-121203
Pick-to: 6.7
Change-Id: Iacda16d8dbddf5b8219c290fac473d78c073576e
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
A triangle could be mis-assigned to the wrong path element if a
point could be found in multiple sub-paths. This change uses a
QMultiHash instead of a QHash to look up the points from the
triangulator, and chooses the path element that has the
triangle on the fill side.
Pick-to: 6.7
Change-Id: Ic2773da5c7b4a64386e20c19745ce36e2dcb2c57
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
|
| |
|
|
|
|
|
|
|
| |
This issue was found in fonts where intersection match a vertex of the
path. With this change we take care of such points properly.
Pick-to: 6.7
Change-Id: Ibe2f0334e748351066e324f8bb10774fc505e832
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
|
| |
|
|
|
|
|
|
|
|
| |
We don't need to do expensive operations if we already know that
the path is well behaved.
Task-number: QTBUG-112340
Pick-to: 6.7
Change-Id: Ic386b7f293045c28294f56ad433bdae2b3b6b0e5
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
| |
|
|
|
|
| |
Pick-to: 6.7
Change-Id: I7fc0087c4f9219ac6834008e2c49438f81aae3d9
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Currently the CurveRenderer is not working when the path is
self-intersecting.
With this patch, the self-intersections are removed before the
path is used for filling (optionally, default: on) The stroking
path is untouched.
The function findOverlappingCandidates finds candidates of elements
that might be intersecting. Its complexity is O(n log n) and can
also be used in other parts of the code where overlapping bounding
triangles need to be identified.
The function solveIntersections removes all intersections from
a QQuadPath. If intersections are solved, the path is oriented such
that the filling is on the right side of the path. If no intersections
are found, the path is returned without any changes. The optional
argument alwaysReorder can be used to force a reordering of the paths,
such that the filling of the shape is always on the right side of the
path.
Intersections are found with Newtons algorithm with 9 different
starting values. This is reliable in finding all intersections but
the starting values could be improved/reduced to improve performance.
Pick-to: 6.7
Change-Id: I088e4edfff755155521ed91114bc67f63c6e546a
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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 <paul.tvete@qt.io>
|
|
|
This moves the internals of the curve renderer out from
Qt Quick Shapes and into a more centralized location
in Qt Quick, so that we can use the same code to create
a new text backend for rendering large scale text without
artifacts.
Change-Id: I3f7e6f7961c1bbe230fcb531c0ca028e038c1afd
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
|