aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/quick/shapes/content/item10.qml19
-rw-r--r--src/imports/shapes/plugin.cpp1
-rw-r--r--src/imports/shapes/qquickshape.cpp83
-rw-r--r--src/imports/shapes/qquickshape_p.h30
-rw-r--r--src/imports/shapes/qquickshapegenericrenderer.cpp109
-rw-r--r--src/imports/shapes/qquickshapegenericrenderer_p.h49
-rw-r--r--src/imports/shapes/qquickshapenvprrenderer.cpp58
-rw-r--r--src/imports/shapes/qquickshapenvprrenderer_p.h1
-rw-r--r--src/imports/shapes/qquickshapesoftwarerenderer.cpp4
-rw-r--r--src/imports/shapes/shaders/conicalgradient.frag19
-rw-r--r--src/imports/shapes/shaders/conicalgradient.vert13
-rw-r--r--src/imports/shapes/shaders/conicalgradient_core.frag22
-rw-r--r--src/imports/shapes/shaders/conicalgradient_core.vert15
-rw-r--r--src/imports/shapes/shapes.qrc4
-rw-r--r--tests/auto/quick/qquickshape/data/pathitem6.pngbin0 -> 11024 bytes
-rw-r--r--tests/auto/quick/qquickshape/data/pathitem6.qml35
-rw-r--r--tests/auto/quick/qquickshape/tst_qquickshape.cpp19
-rw-r--r--tests/manual/shapestest/shapestest.qml27
18 files changed, 502 insertions, 6 deletions
diff --git a/examples/quick/shapes/content/item10.qml b/examples/quick/shapes/content/item10.qml
index cb2444fe4b..e91342c2fe 100644
--- a/examples/quick/shapes/content/item10.qml
+++ b/examples/quick/shapes/content/item10.qml
@@ -66,7 +66,18 @@ Rectangle {
ShapePath {
strokeWidth: 4
strokeColor: "black"
- fillColor: "lightBlue"
+ fillGradient: ConicalGradient {
+ id: conGrad
+ centerX: 100; centerY: 75
+ NumberAnimation on angle { from: 0; to: 360; duration: 10000; loops: Animation.Infinite }
+ GradientStop { position: 0; color: "#00000000" }
+ GradientStop { position: 0.10; color: "#ffe0cc73" }
+ GradientStop { position: 0.17; color: "#ffc6a006" }
+ GradientStop { position: 0.46; color: "#ff600659" }
+ GradientStop { position: 0.72; color: "#ff0680ac" }
+ GradientStop { position: 0.92; color: "#ffb9d9e6" }
+ GradientStop { position: 1.00; color: "#00000000" }
+ }
startX: 50; startY: 100
PathCubic {
@@ -154,4 +165,10 @@ Rectangle {
}
}
}
+
+ Text {
+ anchors.right: parent.right
+ anchors.top: parent.top
+ text: "Conical gradient angle: " + Math.round(conGrad.angle)
+ }
}
diff --git a/src/imports/shapes/plugin.cpp b/src/imports/shapes/plugin.cpp
index 186e182192..239ef78e55 100644
--- a/src/imports/shapes/plugin.cpp
+++ b/src/imports/shapes/plugin.cpp
@@ -67,6 +67,7 @@ public:
qmlRegisterUncreatableType<QQuickShapeGradient>(uri, 1, 0, "ShapeGradient", QQuickShapeGradient::tr("ShapeGradient is an abstract base class"));
qmlRegisterType<QQuickShapeLinearGradient>(uri, 1, 0, "LinearGradient");
qmlRegisterType<QQuickShapeRadialGradient>(uri, 1, 0, "RadialGradient");
+ qmlRegisterType<QQuickShapeConicalGradient>(uri, 1, 0, "ConicalGradient");
}
};
diff --git a/src/imports/shapes/qquickshape.cpp b/src/imports/shapes/qquickshape.cpp
index b6174fb177..1ed61ff476 100644
--- a/src/imports/shapes/qquickshape.cpp
+++ b/src/imports/shapes/qquickshape.cpp
@@ -1296,6 +1296,89 @@ void QQuickShapeRadialGradient::setFocalRadius(qreal v)
}
}
+/*!
+ \qmltype ConicalGradient
+ \instantiates QQuickShapeConicalGradient
+ \inqmlmodule QtQuick.Shapes
+ \ingroup qtquick-paths
+ \ingroup qtquick-views
+ \inherits ShapeGradient
+ \brief Conical gradient
+ \since 5.10
+
+ Conical gradients interpolate colors counter-clockwise around a center
+ point in Shape items.
+
+ \note The \l{ShapeGradient.spread}{spread mode} setting has no effect for
+ conical gradients.
+
+ \note ConicalGradient is only supported in combination with Shape items. It
+ is not compatible with \l Rectangle, as that only supports \l Gradient.
+
+ \sa QConicalGradient
+ */
+
+QQuickShapeConicalGradient::QQuickShapeConicalGradient(QObject *parent)
+ : QQuickShapeGradient(parent)
+{
+}
+
+/*!
+ \qmlproperty real QtQuick.Shapes::ConicalGradient::centerX
+ \qmlproperty real QtQuick.Shapes::ConicalGradient::centerY
+
+ These properties define the center point of the conical gradient.
+ */
+
+qreal QQuickShapeConicalGradient::centerX() const
+{
+ return m_centerPoint.x();
+}
+
+void QQuickShapeConicalGradient::setCenterX(qreal v)
+{
+ if (m_centerPoint.x() != v) {
+ m_centerPoint.setX(v);
+ emit centerXChanged();
+ emit updated();
+ }
+}
+
+qreal QQuickShapeConicalGradient::centerY() const
+{
+ return m_centerPoint.y();
+}
+
+void QQuickShapeConicalGradient::setCenterY(qreal v)
+{
+ if (m_centerPoint.y() != v) {
+ m_centerPoint.setY(v);
+ emit centerYChanged();
+ emit updated();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick.Shapes::ConicalGradient::angle
+
+ This property defines the start angle for the conical gradient. The value
+ is in degrees (0-360).
+ */
+
+qreal QQuickShapeConicalGradient::angle() const
+{
+ return m_angle;
+}
+
+void QQuickShapeConicalGradient::setAngle(qreal v)
+{
+ if (m_angle != v) {
+ m_angle = v;
+ emit angleChanged();
+ emit updated();
+ }
+}
+
#if QT_CONFIG(opengl)
// contexts sharing with each other get the same cache instance
diff --git a/src/imports/shapes/qquickshape_p.h b/src/imports/shapes/qquickshape_p.h
index b6943db37c..27b02bc962 100644
--- a/src/imports/shapes/qquickshape_p.h
+++ b/src/imports/shapes/qquickshape_p.h
@@ -167,6 +167,36 @@ private:
qreal m_focalRadius = 0;
};
+class QQuickShapeConicalGradient : public QQuickShapeGradient
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal centerX READ centerX WRITE setCenterX NOTIFY centerXChanged)
+ Q_PROPERTY(qreal centerY READ centerY WRITE setCenterY NOTIFY centerYChanged)
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+ Q_CLASSINFO("DefaultProperty", "stops")
+
+public:
+ QQuickShapeConicalGradient(QObject *parent = nullptr);
+
+ qreal centerX() const;
+ void setCenterX(qreal v);
+
+ qreal centerY() const;
+ void setCenterY(qreal v);
+
+ qreal angle() const;
+ void setAngle(qreal v);
+
+signals:
+ void centerXChanged();
+ void centerYChanged();
+ void angleChanged();
+
+private:
+ QPointF m_centerPoint;
+ qreal m_angle = 0;
+};
+
class QQuickShapePath : public QQuickPath
{
Q_OBJECT
diff --git a/src/imports/shapes/qquickshapegenericrenderer.cpp b/src/imports/shapes/qquickshapegenericrenderer.cpp
index 5a2f337b51..98ba89dc3d 100644
--- a/src/imports/shapes/qquickshapegenericrenderer.cpp
+++ b/src/imports/shapes/qquickshapegenericrenderer.cpp
@@ -105,6 +105,9 @@ void QQuickShapeGenericStrokeFillNode::activateMaterial(Material m)
case MatRadialGradient:
m_material.reset(QQuickShapeGenericMaterialFactory::createRadialGradient(m_window, this));
break;
+ case MatConicalGradient:
+ m_material.reset(QQuickShapeGenericMaterialFactory::createConicalGradient(m_window, this));
+ break;
default:
qWarning("Unknown material %d", m);
return;
@@ -250,6 +253,10 @@ void QQuickShapeGenericRenderer::setFillGradient(int index, QQuickShapeGradient
d.fillGradient.b = QPointF(g->focalX(), g->focalY());
d.fillGradient.v0 = g->centerRadius();
d.fillGradient.v1 = g->focalRadius();
+ } else if (QQuickShapeConicalGradient *g = qobject_cast<QQuickShapeConicalGradient *>(gradient)) {
+ d.fillGradientActive = ConicalGradient;
+ d.fillGradient.a = QPointF(g->centerX(), g->centerY());
+ d.fillGradient.v0 = g->angle();
} else {
Q_UNREACHABLE();
}
@@ -594,6 +601,9 @@ void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGen
case RadialGradient:
gradMat = QQuickShapeGenericStrokeFillNode::MatRadialGradient;
break;
+ case ConicalGradient:
+ gradMat = QQuickShapeGenericStrokeFillNode::MatConicalGradient;
+ break;
default:
Q_UNREACHABLE();
}
@@ -717,6 +727,22 @@ QSGMaterial *QQuickShapeGenericMaterialFactory::createRadialGradient(QQuickWindo
return nullptr;
}
+QSGMaterial *QQuickShapeGenericMaterialFactory::createConicalGradient(QQuickWindow *window,
+ QQuickShapeGenericStrokeFillNode *node)
+{
+ QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
+
+#if QT_CONFIG(opengl)
+ if (api == QSGRendererInterface::OpenGL)
+ return new QQuickShapeConicalGradientMaterial(node);
+#else
+ Q_UNUSED(node);
+#endif
+
+ qWarning("Conical gradient material: Unsupported graphics API %d", api);
+ return nullptr;
+}
+
#if QT_CONFIG(opengl)
QSGMaterialType QQuickShapeLinearGradientShader::type;
@@ -900,6 +926,89 @@ int QQuickShapeRadialGradientMaterial::compare(const QSGMaterial *other) const
return 0;
}
+QSGMaterialType QQuickShapeConicalGradientShader::type;
+
+QQuickShapeConicalGradientShader::QQuickShapeConicalGradientShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex,
+ QStringLiteral(":/qt-project.org/shapes/shaders/conicalgradient.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment,
+ QStringLiteral(":/qt-project.org/shapes/shaders/conicalgradient.frag"));
+}
+
+void QQuickShapeConicalGradientShader::initialize()
+{
+ QOpenGLShaderProgram *prog = program();
+ m_opacityLoc = prog->uniformLocation("opacity");
+ m_matrixLoc = prog->uniformLocation("matrix");
+ m_angleLoc = prog->uniformLocation("angle");
+ m_translationPointLoc = prog->uniformLocation("translationPoint");
+}
+
+void QQuickShapeConicalGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *)
+{
+ QQuickShapeConicalGradientMaterial *m = static_cast<QQuickShapeConicalGradientMaterial *>(mat);
+
+ if (state.isOpacityDirty())
+ program()->setUniformValue(m_opacityLoc, state.opacity());
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrixLoc, state.combinedMatrix());
+
+ QQuickShapeGenericStrokeFillNode *node = m->node();
+
+ const QPointF centerPoint = node->m_fillGradient.a;
+ const GLfloat angle = -qDegreesToRadians(node->m_fillGradient.v0);
+
+ program()->setUniformValue(m_angleLoc, angle);
+ program()->setUniformValue(m_translationPointLoc, centerPoint);
+
+ const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, QQuickShapeGradient::RepeatSpread);
+ QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey);
+ tx->bind();
+}
+
+char const *const *QQuickShapeConicalGradientShader::attributeNames() const
+{
+ static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr };
+ return attr;
+}
+
+int QQuickShapeConicalGradientMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ const QQuickShapeConicalGradientMaterial *m = static_cast<const QQuickShapeConicalGradientMaterial *>(other);
+
+ QQuickShapeGenericStrokeFillNode *a = node();
+ QQuickShapeGenericStrokeFillNode *b = m->node();
+ Q_ASSERT(a && b);
+ if (a == b)
+ return 0;
+
+ const QQuickAbstractPathRenderer::GradientDesc *ga = &a->m_fillGradient;
+ const QQuickAbstractPathRenderer::GradientDesc *gb = &b->m_fillGradient;
+
+ if (int d = ga->a.x() - gb->a.x())
+ return d;
+ if (int d = ga->a.y() - gb->a.y())
+ return d;
+
+ if (int d = ga->v0 - gb->v0)
+ return d;
+
+ if (int d = ga->stops.count() - gb->stops.count())
+ return d;
+
+ for (int i = 0; i < ga->stops.count(); ++i) {
+ if (int d = ga->stops[i].first - gb->stops[i].first)
+ return d;
+ if (int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
+ return d;
+ }
+
+ return 0;
+}
+
#endif // QT_CONFIG(opengl)
QT_END_NAMESPACE
diff --git a/src/imports/shapes/qquickshapegenericrenderer_p.h b/src/imports/shapes/qquickshapegenericrenderer_p.h
index 2561116f81..32cec798ec 100644
--- a/src/imports/shapes/qquickshapegenericrenderer_p.h
+++ b/src/imports/shapes/qquickshapegenericrenderer_p.h
@@ -210,7 +210,8 @@ public:
enum Material {
MatSolidColor,
MatLinearGradient,
- MatRadialGradient
+ MatRadialGradient,
+ MatConicalGradient
};
void activateMaterial(Material m);
@@ -242,6 +243,7 @@ public:
static QSGMaterial *createVertexColor(QQuickWindow *window);
static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
static QSGMaterial *createRadialGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
+ static QSGMaterial *createConicalGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
};
#if QT_CONFIG(opengl)
@@ -343,6 +345,51 @@ private:
QQuickShapeGenericStrokeFillNode *m_node;
};
+class QQuickShapeConicalGradientShader : public QSGMaterialShader
+{
+public:
+ QQuickShapeConicalGradientShader();
+
+ void initialize() override;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
+
+ static QSGMaterialType type;
+
+private:
+ int m_opacityLoc = -1;
+ int m_matrixLoc = -1;
+ int m_angleLoc = -1;
+ int m_translationPointLoc = -1;
+};
+
+class QQuickShapeConicalGradientMaterial : public QSGMaterial
+{
+public:
+ QQuickShapeConicalGradientMaterial(QQuickShapeGenericStrokeFillNode *node)
+ : m_node(node)
+ {
+ setFlag(Blending | RequiresFullMatrix);
+ }
+
+ QSGMaterialType *type() const override
+ {
+ return &QQuickShapeConicalGradientShader::type;
+ }
+
+ int compare(const QSGMaterial *other) const override;
+
+ QSGMaterialShader *createShader() const override
+ {
+ return new QQuickShapeConicalGradientShader;
+ }
+
+ QQuickShapeGenericStrokeFillNode *node() const { return m_node; }
+
+private:
+ QQuickShapeGenericStrokeFillNode *m_node;
+};
+
#endif // QT_CONFIG(opengl)
QT_END_NAMESPACE
diff --git a/src/imports/shapes/qquickshapenvprrenderer.cpp b/src/imports/shapes/qquickshapenvprrenderer.cpp
index a08da2f3fe..27a0d6ca96 100644
--- a/src/imports/shapes/qquickshapenvprrenderer.cpp
+++ b/src/imports/shapes/qquickshapenvprrenderer.cpp
@@ -42,6 +42,7 @@
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
+#include <qmath.h>
#include <private/qquickpath_p_p.h>
QT_BEGIN_NAMESPACE
@@ -138,6 +139,10 @@ void QQuickShapeNvprRenderer::setFillGradient(int index, QQuickShapeGradient *gr
d.fillGradient.b = QPointF(g->focalX(), g->focalY());
d.fillGradient.v0 = g->centerRadius();
d.fillGradient.v1 = g->focalRadius();
+ } else if (QQuickShapeConicalGradient *g = qobject_cast<QQuickShapeConicalGradient *>(gradient)) {
+ d.fillGradientActive = ConicalGradient;
+ d.fillGradient.a = QPointF(g->centerX(), g->centerY());
+ d.fillGradient.v0 = g->angle();
} else {
Q_UNREACHABLE();
}
@@ -536,6 +541,37 @@ QQuickNvprMaterialManager::MaterialDesc *QQuickNvprMaterialManager::activateMate
Q_ASSERT(mtl.uniLoc[4] >= 0);
mtl.uniLoc[5] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "translationPoint");
Q_ASSERT(mtl.uniLoc[5] >= 0);
+ } else if (m == MatConicalGradient) {
+ static const char *fragSrc =
+ "#version 310 es\n"
+ "precision highp float;\n"
+ "#define INVERSE_2PI 0.1591549430918953358\n"
+ "uniform sampler2D gradTab;\n"
+ "uniform float opacity;\n"
+ "uniform float angle;\n"
+ "uniform vec2 translationPoint;\n"
+ "layout(location = 0) in vec2 uv;\n"
+ "out vec4 fragColor;\n"
+ "void main() {\n"
+ " vec2 coord = uv - translationPoint;\n"
+ " float t;\n"
+ " if (abs(coord.y) == abs(coord.x))\n"
+ " t = (atan(-coord.y + 0.002, coord.x) + angle) * INVERSE_2PI;\n"
+ " else\n"
+ " t = (atan(-coord.y, coord.x) + angle) * INVERSE_2PI;\n"
+ " fragColor = texture(gradTab, vec2(t - floor(t), 0.5)) * opacity;\n"
+ "}\n";
+ if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) {
+ qWarning("NVPR: Failed to create shader pipeline for conical gradient");
+ return nullptr;
+ }
+ Q_ASSERT(mtl.ppl && mtl.prg);
+ mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity");
+ Q_ASSERT(mtl.uniLoc[1] >= 0);
+ mtl.uniLoc[2] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "angle");
+ Q_ASSERT(mtl.uniLoc[2] >= 0);
+ mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "translationPoint");
+ Q_ASSERT(mtl.uniLoc[3] >= 0);
} else {
Q_UNREACHABLE();
}
@@ -593,10 +629,7 @@ void QQuickShapeNvprRenderNode::renderFill(ShapePathRenderData *d)
{
QQuickNvprMaterialManager::MaterialDesc *mtl = nullptr;
if (d->fillGradientActive) {
- const QQuickShapeGradientCache::Key cacheKey(d->fillGradient.stops, d->fillGradient.spread);
- QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey);
- tx->bind();
-
+ QQuickShapeGradient::SpreadMode spread = d->fillGradient.spread;
if (d->fillGradientActive == QQuickAbstractPathRenderer::LinearGradient) {
mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatLinearGradient);
// uv = vec2(coeff[0] * x + coeff[1] * y + coeff[2], coeff[3] * x + coeff[4] * y + coeff[5])
@@ -624,9 +657,26 @@ void QQuickShapeNvprRenderNode::renderFill(ShapePathRenderData *d)
f->glProgramUniform1f(mtl->prg, mtl->uniLoc[3], centerRadius);
f->glProgramUniform1f(mtl->prg, mtl->uniLoc[4], focalRadius);
f->glProgramUniform2f(mtl->prg, mtl->uniLoc[5], focalPoint.x(), focalPoint.y());
+ } else if (d->fillGradientActive == QQuickAbstractPathRenderer::ConicalGradient) {
+ mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatConicalGradient);
+ // same old
+ GLfloat coeff[6] = { 1, 0, 0,
+ 0, 1, 0 };
+ nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff);
+
+ const QPointF centerPoint = d->fillGradient.a;
+ const GLfloat angle = -qDegreesToRadians(d->fillGradient.v0);
+
+ f->glProgramUniform1f(mtl->prg, mtl->uniLoc[2], angle);
+ f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], centerPoint.x(), centerPoint.y());
+
+ spread = QQuickShapeGradient::RepeatSpread;
} else {
Q_UNREACHABLE();
}
+ const QQuickShapeGradientCache::Key cacheKey(d->fillGradient.stops, spread);
+ QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey);
+ tx->bind();
} else {
mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid);
f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0],
diff --git a/src/imports/shapes/qquickshapenvprrenderer_p.h b/src/imports/shapes/qquickshapenvprrenderer_p.h
index b3d92dbdbc..f6c9fc169e 100644
--- a/src/imports/shapes/qquickshapenvprrenderer_p.h
+++ b/src/imports/shapes/qquickshapenvprrenderer_p.h
@@ -137,6 +137,7 @@ public:
MatSolid,
MatLinearGradient,
MatRadialGradient,
+ MatConicalGradient,
NMaterials
};
diff --git a/src/imports/shapes/qquickshapesoftwarerenderer.cpp b/src/imports/shapes/qquickshapesoftwarerenderer.cpp
index 15803dcf0a..ed13afbc7e 100644
--- a/src/imports/shapes/qquickshapesoftwarerenderer.cpp
+++ b/src/imports/shapes/qquickshapesoftwarerenderer.cpp
@@ -160,6 +160,10 @@ void QQuickShapeSoftwareRenderer::setFillGradient(int index, QQuickShapeGradient
g->focalX(), g->focalY(), g->focalRadius());
setupPainterGradient(&painterGradient, *g);
d.brush = QBrush(painterGradient);
+ } else if (QQuickShapeConicalGradient *g = qobject_cast<QQuickShapeConicalGradient *>(gradient)) {
+ QConicalGradient painterGradient(g->centerX(), g->centerY(), g->angle());
+ setupPainterGradient(&painterGradient, *g);
+ d.brush = QBrush(painterGradient);
} else {
d.brush = QBrush(d.fillColor);
}
diff --git a/src/imports/shapes/shaders/conicalgradient.frag b/src/imports/shapes/shaders/conicalgradient.frag
new file mode 100644
index 0000000000..af5fdd5ee0
--- /dev/null
+++ b/src/imports/shapes/shaders/conicalgradient.frag
@@ -0,0 +1,19 @@
+#define INVERSE_2PI 0.1591549430918953358
+
+uniform sampler2D gradTabTexture;
+uniform lowp float opacity;
+
+uniform highp float angle;
+
+varying highp vec2 coord;
+
+void main()
+{
+ highp float t;
+ if (abs(coord.y) == abs(coord.x))
+ t = (atan(-coord.y + 0.002, coord.x) + angle) * INVERSE_2PI;
+ else
+ t = (atan(-coord.y, coord.x) + angle) * INVERSE_2PI;
+ gl_FragColor = texture2D(gradTabTexture, vec2(t - floor(t), 0.5)) * opacity;
+
+}
diff --git a/src/imports/shapes/shaders/conicalgradient.vert b/src/imports/shapes/shaders/conicalgradient.vert
new file mode 100644
index 0000000000..3350b0675a
--- /dev/null
+++ b/src/imports/shapes/shaders/conicalgradient.vert
@@ -0,0 +1,13 @@
+attribute vec4 vertexCoord;
+attribute vec4 vertexColor;
+
+uniform mat4 matrix;
+uniform vec2 translationPoint;
+
+varying vec2 coord;
+
+void main()
+{
+ coord = vertexCoord.xy - translationPoint;
+ gl_Position = matrix * vertexCoord;
+}
diff --git a/src/imports/shapes/shaders/conicalgradient_core.frag b/src/imports/shapes/shaders/conicalgradient_core.frag
new file mode 100644
index 0000000000..e18b80159a
--- /dev/null
+++ b/src/imports/shapes/shaders/conicalgradient_core.frag
@@ -0,0 +1,22 @@
+#version 150 core
+
+#define INVERSE_2PI 0.1591549430918953358
+
+uniform sampler2D gradTabTexture;
+uniform float opacity;
+
+uniform float angle;
+
+in vec2 coord;
+
+out vec4 fragColor;
+
+void main()
+{
+ float t;
+ if (abs(coord.y) == abs(coord.x))
+ t = (atan(-coord.y + 0.002, coord.x) + angle) * INVERSE_2PI;
+ else
+ t = (atan(-coord.y, coord.x) + angle) * INVERSE_2PI;
+ fragColor = texture(gradTabTexture, vec2(t - floor(t), 0.5)) * opacity;
+}
diff --git a/src/imports/shapes/shaders/conicalgradient_core.vert b/src/imports/shapes/shaders/conicalgradient_core.vert
new file mode 100644
index 0000000000..f94a56401b
--- /dev/null
+++ b/src/imports/shapes/shaders/conicalgradient_core.vert
@@ -0,0 +1,15 @@
+#version 150 core
+
+in vec4 vertexCoord;
+in vec4 vertexColor;
+
+uniform mat4 matrix;
+uniform vec2 translationPoint;
+
+out vec2 coord;
+
+void main()
+{
+ coord = vertexCoord.xy - translationPoint;
+ gl_Position = matrix * vertexCoord;
+}
diff --git a/src/imports/shapes/shapes.qrc b/src/imports/shapes/shapes.qrc
index 92912ede48..f139861693 100644
--- a/src/imports/shapes/shapes.qrc
+++ b/src/imports/shapes/shapes.qrc
@@ -12,5 +12,9 @@
<file>shaders/radialgradient.frag</file>
<file>shaders/radialgradient_core.vert</file>
<file>shaders/radialgradient_core.frag</file>
+ <file>shaders/conicalgradient.vert</file>
+ <file>shaders/conicalgradient.frag</file>
+ <file>shaders/conicalgradient_core.vert</file>
+ <file>shaders/conicalgradient_core.frag</file>
</qresource>
</RCC>
diff --git a/tests/auto/quick/qquickshape/data/pathitem6.png b/tests/auto/quick/qquickshape/data/pathitem6.png
new file mode 100644
index 0000000000..d9e53d6c00
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/pathitem6.png
Binary files differ
diff --git a/tests/auto/quick/qquickshape/data/pathitem6.qml b/tests/auto/quick/qquickshape/data/pathitem6.qml
new file mode 100644
index 0000000000..fafcc48196
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/pathitem6.qml
@@ -0,0 +1,35 @@
+import QtQuick 2.9
+import tst_qquickpathitem 1.0
+
+Item {
+ width: 200
+ height: 150
+
+ Shape {
+ vendorExtensionsEnabled: false
+ objectName: "pathItem"
+ anchors.fill: parent
+
+ ShapePath {
+ strokeWidth: 4
+ strokeColor: "red"
+ fillGradient: ConicalGradient {
+ centerX: 100; centerY: 100; angle: 45
+ GradientStop { position: 0; color: "#00000000" }
+ GradientStop { position: 0.10; color: "#ffe0cc73" }
+ GradientStop { position: 0.17; color: "#ffc6a006" }
+ GradientStop { position: 0.46; color: "#ff600659" }
+ GradientStop { position: 0.72; color: "#ff0680ac" }
+ GradientStop { position: 0.92; color: "#ffb9d9e6" }
+ GradientStop { position: 1.00; color: "#00000000" }
+ }
+ fillColor: "blue" // ignored with the gradient set
+ strokeStyle: ShapePath.DashLine
+ dashPattern: [ 1, 4 ]
+ startX: 20; startY: 20
+ PathLine { x: 180; y: 130 }
+ PathLine { x: 20; y: 130 }
+ PathLine { x: 20; y: 20 }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
index a779b23abd..1b5b345d19 100644
--- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp
+++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
@@ -56,6 +56,7 @@ private slots:
void render();
void renderWithMultipleSp();
void radialGrad();
+ void conicalGrad();
};
tst_QQuickShape::tst_QQuickShape()
@@ -69,6 +70,7 @@ tst_QQuickShape::tst_QQuickShape()
qmlRegisterUncreatableType<QQuickShapeGradient>(uri, 1, 0, "ShapeGradient", QQuickShapeGradient::tr("ShapeGradient is an abstract base class"));
qmlRegisterType<QQuickShapeLinearGradient>(uri, 1, 0, "LinearGradient");
qmlRegisterType<QQuickShapeRadialGradient>(uri, 1, 0, "RadialGradient");
+ qmlRegisterType<QQuickShapeConicalGradient>(uri, 1, 0, "ConicalGradient");
}
void tst_QQuickShape::initValues()
@@ -264,6 +266,23 @@ void tst_QQuickShape::radialGrad()
QVERIFY(QQuickVisualTestUtil::compareImages(img.convertToFormat(refImg.format()), refImg));
}
+void tst_QQuickShape::conicalGrad()
+{
+ QScopedPointer<QQuickView> window(createView());
+
+ window->setSource(testFileUrl("pathitem6.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("pathitem6.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QVERIFY(QQuickVisualTestUtil::compareImages(img.convertToFormat(refImg.format()), refImg));
+}
+
QTEST_MAIN(tst_QQuickShape)
#include "tst_qquickshape.moc"
diff --git a/tests/manual/shapestest/shapestest.qml b/tests/manual/shapestest/shapestest.qml
index d3f946b227..de9e20b8f3 100644
--- a/tests/manual/shapestest/shapestest.qml
+++ b/tests/manual/shapestest/shapestest.qml
@@ -401,6 +401,33 @@ Rectangle {
}
}
}
+
+ Rectangle {
+ border.color: "purple"
+ color: "transparent"
+ width: 200
+ height: 100
+ Shape {
+ anchors.fill: parent
+ ShapePath {
+ strokeWidth: -1
+ strokeColor: "red"
+ fillGradient: ConicalGradient {
+ centerX: 100; centerY: 50
+ angle: 90
+ GradientStop { position: 0; color: "blue" }
+ GradientStop { position: 0.2; color: "green" }
+ GradientStop { position: 0.4; color: "red" }
+ GradientStop { position: 0.6; color: "yellow" }
+ GradientStop { position: 1; color: "cyan" }
+ }
+ PathLine { x: 0; y: 100 }
+ PathLine { x: 200; y: 100 }
+ PathLine { x: 200; y: 0 }
+ PathLine { x: 0; y: 0 }
+ }
+ }
+ }
}
}