aboutsummaryrefslogtreecommitdiffstats
path: root/src/quickshapes/qquickshape.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quickshapes/qquickshape.cpp')
-rw-r--r--src/quickshapes/qquickshape.cpp538
1 files changed, 400 insertions, 138 deletions
diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp
index 494047d8e8..6505adcb39 100644
--- a/src/quickshapes/qquickshape.cpp
+++ b/src/quickshapes/qquickshape.cpp
@@ -5,17 +5,18 @@
#include "qquickshape_p_p.h"
#include "qquickshapegenericrenderer_p.h"
#include "qquickshapesoftwarerenderer_p.h"
+#include "qquickshapecurverenderer_p.h"
#include <private/qsgplaintexture_p.h>
#include <private/qquicksvgparser_p.h>
#include <QtGui/private/qdrawhelper_p.h>
#include <QOpenGLFunctions>
#include <QLoggingCategory>
-#include <QtGui/private/qrhi_p.h>
+#include <rhi/qrhi.h>
static void initResources()
{
#if defined(QT_STATIC)
- Q_INIT_RESOURCE(qtquickshapes);
+ Q_INIT_RESOURCE(qtquickshapes_shaders);
#endif
}
@@ -34,6 +35,35 @@ Q_LOGGING_CATEGORY(QQSHAPE_LOG_TIME_DIRTY_SYNC, "qt.shape.time.sync")
\qml
import QtQuick.Shapes
\endqml
+
+ Qt Quick Shapes provides tools for drawing arbitrary shapes in a Qt Quick scene.
+ \l{Shape}{Shapes} can be constructed from basic building blocks like \l{PathLine}{lines} and
+ \l{PathCubic}{curves} that define sub-shapes. The sub-shapes can then be filled with solid
+ colors or gradients, and an outline stroke can be defined.
+
+ Qt Quick Shapes also supports higher level path element types, such as \l{PathText}{text} and
+ \l{PathSvg}{SVG path descriptions}. The currently supported element types is: PathMove,
+ PathLine, PathQuad, PathCubic, PathArc, PathText and PathSvg.
+
+ Qt Quick Shapes triangulates the shapes and renders the corresponding triangles on the GPU.
+ Therefore, altering the control points of elements will lead to re-triangulation of the
+ affected paths, at some performance cost. In addition, curves are flattened before they are
+ rendered, so applying a very high scale to the shape may show artifacts where it is visible
+ that the curves are represented by a sequence of smaller, straight lines.
+
+ \note By default, Qt Quick Shapes relies on multi-sampling for anti-aliasing. This can be
+ enabled for the entire application or window using the corresponding settings in QSurfaceFormat.
+ It can also be enabled for only the shape, by setting its \l{Item::layer.enabled}{layer.enabled}
+ property to true and then adjusting the \l{Item::layer.samples}{layer.samples} property. In the
+ latter case, multi-sampling will not be applied to the entire scene, but the shape will be
+ rendered via an intermediate off-screen buffer. Alternatively, the
+ \l{QtQuick.Shapes::Shape::preferredRendererType}{preferredRendererType} property can be set
+ to \c{Shape.CurveRenderer}. This has anti-aliasing built in and generally renders the shapes
+ at a higher quality, but at some additional performance cost.
+
+ For further information, the \l{Qt Quick Examples - Shapes}{Shapes example} shows how to
+ implement different types of shapes, fills and strokes, and the \l{Weather Forecast Example}
+ shows examples of different ways shapes might be useful in a user interface.
*/
void QQuickShapes_initializeModule()
@@ -119,7 +149,7 @@ QQuickShapeStrokeFillParams::QQuickShapeStrokeFillParams()
\image visualpath-code-example.png
- \sa {Qt Quick Examples - Shapes}, Shape
+ \sa {Qt Quick Examples - Shapes}, {Weather Forecast Example}, Shape
*/
QQuickShapePathPrivate::QQuickShapePathPrivate()
@@ -360,10 +390,8 @@ void QQuickShapePath::setCapStyle(CapStyle style)
This property defines the style of stroking. The default value is
ShapePath.SolidLine.
- \list
- \li ShapePath.SolidLine - A plain line.
- \li ShapePath.DashLine - Dashes separated by a few pixels.
- \endlist
+ \value ShapePath.SolidLine A plain line.
+ \value ShapePath.DashLine Dashes separated by a few pixels.
*/
QQuickShapePath::StrokeStyle QQuickShapePath::strokeStyle() const
@@ -491,6 +519,83 @@ void QQuickShapePath::resetFillGradient()
}
/*!
+ \qmlproperty PathHints QtQuick.Shapes::ShapePath::pathHints
+ \since 6.7
+
+ This property describes characteristics of the shape. If set, these hints may allow
+ optimized rendering. By default, no hints are set. It can be a combination of the following
+ values:
+
+ \value ShapePath.PathLinear
+ The path only has straight lines, no curves.
+ \value ShapePath.PathQuadratic
+ The path does not have any cubic curves: only lines and quadratic Bezier curves.
+ \value ShapePath.PathConvex
+ The path does not have any dents or holes. All straight lines between two points
+ inside the shape will be completely inside the shape.
+ \value ShapePath.PathFillOnRight
+ The path follows the TrueType convention where outlines around solid fill have their
+ control points ordered clockwise, and outlines around holes in the shape have their
+ control points ordered counter-clockwise.
+ \value ShapePath.PathSolid
+ The path has no holes, or mathematically speaking it is \e{simply connected}.
+ \value ShapePath.PathNonIntersecting
+ The path outline does not cross itself.
+ \value ShapePath.PathNonOverlappingControlPointTriangles
+ The triangles defined by the curve control points do not overlap with each other,
+ or with any of the line segments. Also, no line segments intersect.
+ This implies \c PathNonIntersecting.
+
+ Not all hints are logically independent, but the dependencies are not enforced.
+ For example, \c PathLinear implies \c PathQuadratic, but it is valid to have \c PathLinear
+ without \c PathQuadratic.
+
+ The pathHints property describes a set of statements known to be true; the absence of a hint
+ does not necessarily mean that the corresponding statement is false.
+*/
+
+QQuickShapePath::PathHints QQuickShapePath::pathHints() const
+{
+ Q_D(const QQuickShapePath);
+ return d->pathHints;
+}
+
+void QQuickShapePath::setPathHints(PathHints newPathHints)
+{
+ Q_D(QQuickShapePath);
+ if (d->pathHints == newPathHints)
+ return;
+ d->pathHints = newPathHints;
+ emit pathHintsChanged();
+}
+
+/*!
+ \qmlproperty matrix4x4 QtQuick.Shapes::ShapePath::fillTransform
+ \since 6.8
+
+ This property defines a transform to be applied to the path's fill pattern (gradient). It has
+ no effect if the fill is a solid color or transparent. By default no fill transform is enabled
+ and the value of this property is the \c identity matrix.
+*/
+
+QMatrix4x4 QQuickShapePath::fillTransform() const
+{
+ Q_D(const QQuickShapePath);
+ return d->sfp.fillTransform.matrix();
+}
+
+void QQuickShapePath::setFillTransform(const QMatrix4x4 &matrix)
+{
+ Q_D(QQuickShapePath);
+ if (d->sfp.fillTransform != matrix) {
+ d->sfp.fillTransform.setMatrix(matrix);
+ d->dirty |= QQuickShapePathPrivate::DirtyFillTransform;
+ emit fillTransformChanged();
+ emit shapePathChanged();
+ }
+}
+
+/*!
\qmltype Shape
//! \instantiates QQuickShape
\inqmlmodule QtQuick.Shapes
@@ -514,7 +619,7 @@ void QQuickShapePath::resetFillGradient()
Shape. However, not all Shape implementations support all path
element types, while some may not make sense for PathView. Shape's
currently supported subset is: PathMove, PathLine, PathQuad, PathCubic,
- PathArc, and PathSvg.
+ PathArc, PathText and PathSvg.
See \l Path for a detailed overview of the supported path elements.
@@ -598,7 +703,7 @@ void QQuickShapePath::resetFillGradient()
\endlist
- \sa {Qt Quick Examples - Shapes}, Path, PathMove, PathLine, PathQuad, PathCubic, PathArc, PathSvg
+ \sa {Qt Quick Examples - Shapes}, {Weather Forecast Example}, Path, PathMove, PathLine, PathQuad, PathCubic, PathArc, PathSvg
*/
QQuickShapePrivate::QQuickShapePrivate()
@@ -616,6 +721,9 @@ void QQuickShapePrivate::_q_shapePathChanged()
Q_Q(QQuickShape);
spChanged = true;
q->polish();
+ emit q->boundingRectChanged();
+ auto br = q->boundingRect();
+ q->setImplicitSize(br.right(), br.bottom());
}
void QQuickShapePrivate::setStatus(QQuickShape::Status newStatus)
@@ -627,6 +735,18 @@ void QQuickShapePrivate::setStatus(QQuickShape::Status newStatus)
}
}
+qreal QQuickShapePrivate::getImplicitWidth() const
+{
+ Q_Q(const QQuickShape);
+ return q->boundingRect().right();
+}
+
+qreal QQuickShapePrivate::getImplicitHeight() const
+{
+ Q_Q(const QQuickShape);
+ return q->boundingRect().bottom();
+}
+
QQuickShape::QQuickShape(QQuickItem *parent)
: QQuickItem(*(new QQuickShapePrivate), parent)
{
@@ -639,6 +759,7 @@ QQuickShape::~QQuickShape()
/*!
\qmlproperty enumeration QtQuick.Shapes::Shape::rendererType
+ \readonly
This property determines which path rendering backend is active.
@@ -646,15 +767,33 @@ QQuickShape::~QQuickShape()
The renderer is unknown.
\value Shape.GeometryRenderer
- The generic, driver independent solution for OpenGL. Uses the same
+ The generic, driver independent solution for GPU rendering. Uses the same
CPU-based triangulation approach as QPainter's OpenGL 2 paint
- engine. This is the default when the OpenGL Qt Quick scenegraph
+ engine. This is the default when the RHI-based Qt Quick scenegraph
backend is in use.
\value Shape.SoftwareRenderer
Pure QPainter drawing using the raster paint engine. This is the
default, and only, option when the Qt Quick scenegraph is running
with the \c software backend.
+
+ \value Shape.CurveRenderer
+ GPU-based renderer that aims to preserve curvature at any scale.
+ In contrast to \c Shape.GeometryRenderer, curves are not approximated by short straight
+ lines. Instead, curves are rendered using a specialized fragment shader. This improves
+ visual quality and avoids re-tesselation performance hit when zooming. Also,
+ \c Shape.CurveRenderer provides native, high-quality anti-aliasing, without the
+ performance cost of multi- or supersampling.
+
+ By default, \c Shape.GeometryRenderer will be selected unless the Qt Quick scenegraph is running
+ with the \c software backend. In that case, \c Shape.SoftwareRenderer will be used.
+ \c Shape.CurveRenderer may be requested using the \l preferredRendererType property.
+
+ \note The \c Shape.CurveRenderer will approximate cubic curves with quadratic ones and may
+ therefore diverge slightly from the mathematically correct visualization of the shape. In
+ addition, if the shape is being rendered into a Qt Quick 3D scene and the OpenGL backend for
+ RHI is active, the \c GL_OES_standard_derivatives extension to OpenGL is required (this is
+ available by default on OpenGL ES 3 and later, but optional in OpenGL ES 2.)
*/
QQuickShape::RendererType QQuickShape::rendererType() const
@@ -664,12 +803,58 @@ QQuickShape::RendererType QQuickShape::rendererType() const
}
/*!
+ \qmlproperty enumeration QtQuick.Shapes::Shape::preferredRendererType
+ \since 6.6
+
+ Requests a specific backend to use for rendering the shape. The possible values are the same as
+ for \l rendererType. The default is \c Shape.UnknownRenderer, indicating no particular preference.
+
+ If the requested renderer type is not supported for the current Qt Quick backend, the default
+ renderer for that backend will be used instead. This will be reflected in the \l rendererType
+ when the backend is initialized.
+
+ \c Shape.SoftwareRenderer can currently not be selected without running the scenegraph with
+ the \c software backend, in which case it will be selected regardless of the
+ \c preferredRendererType.
+
+ See \l rendererType for more information on the implications.
+*/
+
+QQuickShape::RendererType QQuickShape::preferredRendererType() const
+{
+ Q_D(const QQuickShape);
+ return d->preferredType;
+}
+
+void QQuickShape::setPreferredRendererType(QQuickShape::RendererType preferredType)
+{
+ Q_D(QQuickShape);
+ if (d->preferredType == preferredType)
+ return;
+
+ d->preferredType = preferredType;
+ // (could bail out here if selectRenderType shows no change?)
+
+ for (int i = 0; i < d->sp.size(); ++i) {
+ QQuickShapePath *p = d->sp[i];
+ QQuickShapePathPrivate *pp = QQuickShapePathPrivate::get(p);
+ pp->dirty |= QQuickShapePathPrivate::DirtyAll;
+ }
+ d->spChanged = true;
+ d->_q_shapePathChanged();
+ polish();
+ update();
+
+ emit preferredRendererTypeChanged();
+}
+
+/*!
\qmlproperty bool QtQuick.Shapes::Shape::asynchronous
- When rendererType is \c Shape.GeometryRenderer, the input path is
- triangulated on the CPU during the polishing phase of the Shape. This is
- potentially expensive. To offload this work to separate worker threads,
- set this property to \c true.
+ When rendererType is \c Shape.GeometryRenderer or \c Shape.CurveRenderer, a certain amount of
+ preprocessing of the input path is performed on the CPU during the polishing phase of the
+ Shape. This is potentially expensive. To offload this work to separate worker threads, set this
+ property to \c true.
When enabled, making a Shape visible will not wait for the content to
become available. Instead, the GUI/main thread is not blocked and the
@@ -697,6 +882,26 @@ void QQuickShape::setAsynchronous(bool async)
}
/*!
+ \qmlproperty rect QtQuick.Shapes::Shape::boundingRect
+ \readonly
+ \since 6.6
+
+ Contains the united bounding rect of all sub paths in the shape.
+ */
+QRectF QQuickShape::boundingRect() const
+{
+ Q_D(const QQuickShape);
+ QRectF brect;
+ for (QQuickShapePath *path : d->sp) {
+ qreal pw = path->strokeColor().alpha() ? path->strokeWidth() : 0;
+ qreal d = path->capStyle() == QQuickShapePath::SquareCap ? pw * M_SQRT1_2 : pw / 2;
+ brect = brect.united(path->path().boundingRect().adjusted(-d, -d, d, d));
+ }
+
+ return brect;
+}
+
+/*!
\qmlproperty bool QtQuick.Shapes::Shape::vendorExtensionsEnabled
This property controls the usage of non-standard OpenGL extensions.
@@ -723,6 +928,7 @@ void QQuickShape::setVendorExtensionsEnabled(bool enable)
/*!
\qmlproperty enumeration QtQuick.Shapes::Shape::status
+ \readonly
This property determines the status of the Shape and is relevant when
Shape.asynchronous is set to \c true.
@@ -799,6 +1005,80 @@ bool QQuickShape::contains(const QPointF &point) const
return false;
}
+/*!
+ \qmlproperty enumeration QtQuick.Shapes::Shape::fillMode
+ \since QtQuick.Shapes 6.7
+
+ Set this property to define what happens when the path has a different size
+ than the item.
+
+ \value Shape.NoResize the shape is rendered at its native size, independent of the size of the item. This is the default
+ \value Shape.Stretch the shape is scaled to fit the item, changing the aspect ratio if necessary.
+ Note that non-uniform scaling may cause reduced quality of anti-aliasing when using the curve renderer
+ \value Shape.PreserveAspectFit the shape is scaled uniformly to fit inside the item
+ \value Shape.PreserveAspectCrop the shape is scaled uniformly to fill the item fully, extending outside the item if necessary.
+ Note that this only actually crops the content if \l clip is true
+*/
+
+QQuickShape::FillMode QQuickShape::fillMode() const
+{
+ Q_D(const QQuickShape);
+ return d->fillMode;
+}
+
+void QQuickShape::setFillMode(FillMode newFillMode)
+{
+ Q_D(QQuickShape);
+ if (d->fillMode == newFillMode)
+ return;
+ d->fillMode = newFillMode;
+ emit fillModeChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Shapes::Shape::horizontalAlignment
+ \qmlproperty enumeration QtQuick.Shapes::Shape::verticalAlignment
+ \since 6.7
+
+ Sets the horizontal and vertical alignment of the shape within the item.
+ By default, the shape is aligned with \c{(0,0)} on the top left corner.
+
+ The valid values for \c horizontalAlignment are \c Shape.AlignLeft,
+ \c Shape.AlignRight and \c Shape.AlignHCenter. The valid values for
+ \c verticalAlignment are \c Shape.AlignTop, \c Shape.AlignBottom and
+ \c Shape.AlignVCenter.
+*/
+
+QQuickShape::HAlignment QQuickShape::horizontalAlignment() const
+{
+ Q_D(const QQuickShape);
+ return d->horizontalAlignment;
+}
+
+void QQuickShape::setHorizontalAlignment(HAlignment newHorizontalAlignment)
+{
+ Q_D(QQuickShape);
+ if (d->horizontalAlignment == newHorizontalAlignment)
+ return;
+ d->horizontalAlignment = newHorizontalAlignment;
+ emit horizontalAlignmentChanged();
+}
+
+QQuickShape::VAlignment QQuickShape::verticalAlignment() const
+{
+ Q_D(const QQuickShape);
+ return d->verticalAlignment;
+}
+
+void QQuickShape::setVerticalAlignment(VAlignment newVerticalAlignment)
+{
+ Q_D(QQuickShape);
+ if (d->verticalAlignment == newVerticalAlignment)
+ return;
+ d->verticalAlignment = newVerticalAlignment;
+ emit verticalAlignmentChanged();
+}
+
static void vpe_append(QQmlListProperty<QObject> *property, QObject *obj)
{
QQuickShape *item = static_cast<QQuickShape *>(property->object);
@@ -879,6 +1159,12 @@ void QQuickShape::updatePolish()
d->spChanged = false;
d->effectRefCount = currentEffectRefCount;
+ QQuickShape::RendererType expectedRenderer = d->selectRendererType();
+ if (d->rendererType != expectedRenderer) {
+ delete d->renderer;
+ d->renderer = nullptr;
+ }
+
if (!d->renderer) {
d->createRenderer();
if (!d->renderer)
@@ -913,38 +1199,108 @@ QSGNode *QQuickShape::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
// Called on the render thread, with the gui thread blocked. We can now
// safely access gui thread data.
-
Q_D(QQuickShape);
- if (d->renderer) {
- if (!node)
+
+ if (d->renderer || d->rendererChanged) {
+ if (!node || d->rendererChanged) {
+ d->rendererChanged = false;
+ delete node;
node = d->createNode();
- d->renderer->updateNode();
+ }
+ if (d->renderer)
+ d->renderer->updateNode();
+
+ // TODO: only add transform node when needed (and then make sure static_cast is safe)
+ QMatrix4x4 fillModeTransform;
+ qreal xScale = 1.0;
+ qreal yScale = 1.0;
+
+ if (d->fillMode != NoResize) {
+ xScale = width() / implicitWidth();
+ yScale = height() / implicitHeight();
+
+ if (d->fillMode == PreserveAspectFit)
+ xScale = yScale = qMin(xScale, yScale);
+ else if (d->fillMode == PreserveAspectCrop)
+ xScale = yScale = qMax(xScale, yScale);
+ fillModeTransform.scale(xScale, yScale);
+ }
+ if (d->horizontalAlignment != AlignLeft || d->verticalAlignment != AlignTop) {
+ qreal tx = 0;
+ qreal ty = 0;
+ qreal w = xScale * implicitWidth();
+ qreal h = yScale * implicitHeight();
+ if (d->horizontalAlignment == AlignRight)
+ tx = width() - w;
+ else if (d->horizontalAlignment == AlignHCenter)
+ tx = (width() - w) / 2;
+ if (d->verticalAlignment == AlignBottom)
+ ty = height() - h;
+ else if (d->verticalAlignment == AlignVCenter)
+ ty = (height() - h) / 2;
+ fillModeTransform.translate(tx / xScale, ty / yScale);
+ }
+ static_cast<QSGTransformNode *>(node)->setMatrix(fillModeTransform);
}
return node;
}
-// the renderer object lives on the gui thread
-void QQuickShapePrivate::createRenderer()
+QQuickShape::RendererType QQuickShapePrivate::selectRendererType()
{
+ QQuickShape::RendererType res = QQuickShape::UnknownRenderer;
Q_Q(QQuickShape);
QSGRendererInterface *ri = q->window()->rendererInterface();
if (!ri)
- return;
+ return res;
+
+ static const bool environmentPreferCurve =
+ qEnvironmentVariable("QT_QUICKSHAPES_BACKEND").toLower() == QLatin1String("curverenderer");
switch (ri->graphicsApi()) {
case QSGRendererInterface::Software:
- rendererType = QQuickShape::SoftwareRenderer;
- renderer = new QQuickShapeSoftwareRenderer;
+ res = QQuickShape::SoftwareRenderer;
break;
default:
if (QSGRendererInterface::isApiRhiBased(ri->graphicsApi())) {
- rendererType = QQuickShape::GeometryRenderer;
- renderer = new QQuickShapeGenericRenderer(q);
+ if (preferredType == QQuickShape::CurveRenderer || environmentPreferCurve) {
+ res = QQuickShape::CurveRenderer;
+ } else {
+ res = QQuickShape::GeometryRenderer;
+ }
} else {
qWarning("No path backend for this graphics API yet");
}
break;
}
+
+ return res;
+}
+
+// the renderer object lives on the gui thread
+void QQuickShapePrivate::createRenderer()
+{
+ Q_Q(QQuickShape);
+ QQuickShape::RendererType selectedType = selectRendererType();
+ if (selectedType == QQuickShape::UnknownRenderer)
+ return;
+
+ rendererType = selectedType;
+ rendererChanged = true;
+
+ switch (selectedType) {
+ case QQuickShape::SoftwareRenderer:
+ renderer = new QQuickShapeSoftwareRenderer;
+ break;
+ case QQuickShape::GeometryRenderer:
+ renderer = new QQuickShapeGenericRenderer(q);
+ break;
+ case QQuickShape::CurveRenderer:
+ renderer = new QQuickShapeCurveRenderer(q);
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
}
// the node lives on the render thread
@@ -952,29 +1308,39 @@ QSGNode *QQuickShapePrivate::createNode()
{
Q_Q(QQuickShape);
QSGNode *node = nullptr;
- if (!q->window())
+ if (!q->window() || !renderer)
return node;
QSGRendererInterface *ri = q->window()->rendererInterface();
if (!ri)
return node;
+ QSGNode *pathNode = nullptr;
switch (ri->graphicsApi()) {
case QSGRendererInterface::Software:
- node = new QQuickShapeSoftwareRenderNode(q);
+ pathNode = new QQuickShapeSoftwareRenderNode(q);
static_cast<QQuickShapeSoftwareRenderer *>(renderer)->setNode(
- static_cast<QQuickShapeSoftwareRenderNode *>(node));
+ static_cast<QQuickShapeSoftwareRenderNode *>(pathNode));
break;
default:
if (QSGRendererInterface::isApiRhiBased(ri->graphicsApi())) {
- node = new QQuickShapeGenericNode;
- static_cast<QQuickShapeGenericRenderer *>(renderer)->setRootNode(
- static_cast<QQuickShapeGenericNode *>(node));
+ if (rendererType == QQuickShape::CurveRenderer) {
+ pathNode = new QSGNode;
+ static_cast<QQuickShapeCurveRenderer *>(renderer)->setRootNode(pathNode);
+ } else {
+ pathNode = new QQuickShapeGenericNode;
+ static_cast<QQuickShapeGenericRenderer *>(renderer)->setRootNode(
+ static_cast<QQuickShapeGenericNode *>(pathNode));
+ }
} else {
qWarning("No path backend for this graphics API yet");
}
break;
}
+ // TODO: only create transform node when needed
+ node = new QSGTransformNode;
+ node->appendChildNode(pathNode);
+
return node;
}
@@ -1028,6 +1394,8 @@ void QQuickShapePrivate::sync()
renderer->setStrokeStyle(i, p->strokeStyle(), p->dashOffset(), p->dashPattern());
if (dirty & QQuickShapePathPrivate::DirtyFillGradient)
renderer->setFillGradient(i, p->fillGradient());
+ if (dirty & QQuickShapePathPrivate::DirtyFillTransform)
+ renderer->setFillTransform(i, QQuickShapePathPrivate::get(p)->sfp.fillTransform);
dirty = 0;
}
@@ -1434,112 +1802,6 @@ void QQuickShapeConicalGradient::setAngle(qreal v)
}
}
-static void generateGradientColorTable(const QQuickShapeGradientCacheKey &gradient,
- uint *colorTable, int size, float opacity)
-{
- int pos = 0;
- const QGradientStops &s = gradient.stops;
- Q_ASSERT(!s.isEmpty());
- const bool colorInterpolation = true;
-
- uint alpha = qRound(opacity * 256);
- uint current_color = ARGB_COMBINE_ALPHA(s[0].second.rgba(), alpha);
- qreal incr = 1.0 / qreal(size);
- qreal fpos = 1.5 * incr;
- colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color));
-
- while (fpos <= s.first().first) {
- colorTable[pos] = colorTable[pos - 1];
- pos++;
- fpos += incr;
- }
-
- if (colorInterpolation)
- current_color = qPremultiply(current_color);
-
- const int sLast = s.size() - 1;
- for (int i = 0; i < sLast; ++i) {
- qreal delta = 1/(s[i+1].first - s[i].first);
- uint next_color = ARGB_COMBINE_ALPHA(s[i + 1].second.rgba(), alpha);
- if (colorInterpolation)
- next_color = qPremultiply(next_color);
-
- while (fpos < s[i+1].first && pos < size) {
- int dist = int(256 * ((fpos - s[i].first) * delta));
- int idist = 256 - dist;
- if (colorInterpolation)
- colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
- else
- colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
- ++pos;
- fpos += incr;
- }
- current_color = next_color;
- }
-
- uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
- for ( ; pos < size; ++pos)
- colorTable[pos] = last_color;
-
- colorTable[size-1] = last_color;
-}
-
-QQuickShapeGradientCache::~QQuickShapeGradientCache()
-{
- qDeleteAll(m_textures);
-}
-
-QQuickShapeGradientCache *QQuickShapeGradientCache::cacheForRhi(QRhi *rhi)
-{
- static QHash<QRhi *, QQuickShapeGradientCache *> caches;
- auto it = caches.constFind(rhi);
- if (it != caches.constEnd())
- return *it;
-
- QQuickShapeGradientCache *cache = new QQuickShapeGradientCache;
- rhi->addCleanupCallback([cache](QRhi *rhi) {
- caches.remove(rhi);
- delete cache;
- });
- caches.insert(rhi, cache);
- return cache;
-}
-
-QSGTexture *QQuickShapeGradientCache::get(const QQuickShapeGradientCacheKey &grad)
-{
- QSGPlainTexture *tx = m_textures[grad];
- if (!tx) {
- static const int W = 1024; // texture size is 1024x1
- QImage gradTab(W, 1, QImage::Format_RGBA8888_Premultiplied);
- if (!grad.stops.isEmpty())
- generateGradientColorTable(grad, reinterpret_cast<uint *>(gradTab.bits()), W, 1.0f);
- else
- gradTab.fill(Qt::black);
- tx = new QSGPlainTexture;
- tx->setImage(gradTab);
- switch (grad.spread) {
- case QQuickShapeGradient::PadSpread:
- tx->setHorizontalWrapMode(QSGTexture::ClampToEdge);
- tx->setVerticalWrapMode(QSGTexture::ClampToEdge);
- break;
- case QQuickShapeGradient::RepeatSpread:
- tx->setHorizontalWrapMode(QSGTexture::Repeat);
- tx->setVerticalWrapMode(QSGTexture::Repeat);
- break;
- case QQuickShapeGradient::ReflectSpread:
- tx->setHorizontalWrapMode(QSGTexture::MirroredRepeat);
- tx->setVerticalWrapMode(QSGTexture::MirroredRepeat);
- break;
- default:
- qWarning("Unknown gradient spread mode %d", grad.spread);
- break;
- }
- tx->setFiltering(QSGTexture::Linear);
- m_textures[grad] = tx;
- }
- return tx;
-}
-
QT_END_NAMESPACE
#include "moc_qquickshape_p.cpp"