6#include <QtGui/private/qtriangulator_p.h>
7#include <QtGui/private/qtriangulatingstroker_p.h>
9#include <QSGVertexColorMaterial>
10#include <QSGTextureProvider>
11#include <private/qsgplaintexture_p.h>
13#include <QtQuick/private/qsggradientcache_p.h>
34 c.getRgbF(&r, &g, &b, &a);
36 uchar(qRound(r * a * 255)),
37 uchar(qRound(g * a * 255)),
38 uchar(qRound(b * a * 255)),
39 uchar(qRound(a * 255))
47 setFlag(QSGNode::OwnsGeometry,
true);
48 setFlag(QSGNode::UsePreprocess,
true);
49 setGeometry(
new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0));
50 activateMaterial(window, MatSolidColor);
52 qsgnode_set_description(
this, QLatin1String(
"stroke-fill"));
62 m_material.reset(QQuickShapeGenericMaterialFactory::createVertexColor(window));
64 case MatLinearGradient:
65 m_material.reset(QQuickShapeGenericMaterialFactory::createLinearGradient(window,
this));
67 case MatRadialGradient:
68 m_material.reset(QQuickShapeGenericMaterialFactory::createRadialGradient(window,
this));
70 case MatConicalGradient:
71 m_material.reset(QQuickShapeGenericMaterialFactory::createConicalGradient(window,
this));
74 m_material.reset(QQuickShapeGenericMaterialFactory::createTextureFill(window,
this));
77 qWarning(
"Unknown material %d", m);
81 if (material() != m_material.data())
82 setMaterial(m_material.data());
87 if (m_fillTextureProvider !=
nullptr) {
88 if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(m_fillTextureProvider->texture()))
89 texture->updateTexture();
95 markDirty(QSGNode::DirtyMaterial);
100 m_fillTextureProvider =
nullptr;
101 markDirty(QSGNode::DirtyMaterial);
106 for (ShapePathData &d : m_sp) {
108 d.pendingFill->orphaned =
true;
110 d.pendingStroke->orphaned =
true;
119 for (
int i = totalCount; i < m_sp.size(); i++)
120 setFillTextureProvider(i,
nullptr);
122 if (m_sp.size() != totalCount) {
123 m_sp.resize(totalCount);
125 *countChanged =
true;
127 *countChanged =
false;
129 for (ShapePathData &d : m_sp)
135 ShapePathData &d(m_sp[index]);
142 ShapePathData &d(m_sp[index]);
143 const bool wasTransparent = d.strokeColor
.a == 0;
144 d.strokeColor = colorToColor4ub(color);
145 const bool isTransparent = d.strokeColor
.a == 0;
147 if (wasTransparent && !isTransparent)
153 ShapePathData &d(m_sp[index]);
162 ShapePathData &d(m_sp[index]);
163 d.pen.setCosmetic(c);
171 ShapePathData &d(m_sp[index]);
172 const bool wasTransparent = d.fillColor
.a == 0;
173 d.fillColor = colorToColor4ub(color);
174 const bool isTransparent = d.fillColor
.a == 0;
176 if (wasTransparent && !isTransparent)
182 ShapePathData &d(m_sp[index]);
183 if (d.visible == visible)
188 d.syncDirty |= d.hiddenGeomDirty;
189 d.hiddenGeomDirty = 0;
195 ShapePathData &d(m_sp[index]);
196 d.fillRule = Qt::FillRule(fillRule);
202 ShapePathData &d(m_sp[index]);
203 d.pen.setJoinStyle(Qt::PenJoinStyle(joinStyle));
204 d.pen.setMiterLimit(miterLimit);
210 ShapePathData &d(m_sp[index]);
211 d.pen.setCapStyle(Qt::PenCapStyle(capStyle));
216 qreal dashOffset,
const QList<qreal> &dashPattern)
218 ShapePathData &d(m_sp[index]);
219 d.pen.setStyle(Qt::PenStyle(strokeStyle));
220 if (strokeStyle == QQuickShapePath::DashLine) {
221 d.pen.setDashPattern(dashPattern);
222 d.pen.setDashOffset(dashOffset);
230 Q_ASSERT(dst !=
nullptr);
231 if (gradient ==
nullptr)
232 return QQuickAbstractPathRenderer::NoGradient;
234 dst->stops = gradient->gradientStops();
235 dst->spread = QGradient::Spread(gradient->spread());
236 if (
const QQuickShapeLinearGradient *g = qobject_cast<
const QQuickShapeLinearGradient *>(gradient)) {
237 dst->a = QPointF(g->x1(), g->y1());
238 dst->b = QPointF(g->x2(), g->y2());
240 return QQuickAbstractPathRenderer::LinearGradient;
241 }
else if (
const QQuickShapeRadialGradient *g = qobject_cast<
const QQuickShapeRadialGradient *>(gradient)) {
242 dst->a = QPointF(g->centerX(), g->centerY());
243 dst->b = QPointF(g->focalX(), g->focalY());
244 dst->v0 = g->centerRadius();
245 dst->v1 = g->focalRadius();
247 return QQuickAbstractPathRenderer::RadialGradient;
248 }
else if (
const QQuickShapeConicalGradient *g = qobject_cast<
const QQuickShapeConicalGradient *>(gradient)) {
249 dst->a = QPointF(g->centerX(), g->centerY());
250 dst->v0 = g->angle();
252 return QQuickAbstractPathRenderer::ConicalGradient;
255 Q_UNREACHABLE_RETURN(QQuickAbstractPathRenderer::NoGradient);
260 ShapePathData &d(m_sp[index]);
261 d.fillGradientActive = copyGenericGradient(gradient, &d.fillGradient);
267 ShapePathData &d(m_sp[index]);
268 d.strokeGradientActive = copyGenericGradient(gradient, &d.strokeGradient);
274 ShapePathData &d(m_sp[index]);
275 if ((d.fillTextureProviderItem ==
nullptr) != (textureProviderItem ==
nullptr))
277 if (d.fillTextureProviderItem !=
nullptr)
278 QQuickItemPrivate::get(d.fillTextureProviderItem)->derefWindow();
279 d.fillTextureProviderItem = textureProviderItem;
280 if (d.fillTextureProviderItem !=
nullptr)
281 QQuickItemPrivate::get(d.fillTextureProviderItem)->refWindow(m_item->window());
287 for (
auto &pathData : m_sp) {
288 if (pathData.fillTextureProviderItem !=
nullptr) {
289 if (window ==
nullptr)
290 QQuickItemPrivate::get(pathData.fillTextureProviderItem)->derefWindow();
292 QQuickItemPrivate::get(pathData.fillTextureProviderItem)->refWindow(window);
300 ShapePathData &d(m_sp[index]);
301 d.fillTransform = transform;
307 ShapePathData &d(m_sp[index]);
308 d.triangulationScale = scale;
317 QMetaObject::invokeMethod(qApp, [
this]() { emit done(
this); }, Qt::QueuedConnection);
324 QMetaObject::invokeMethod(qApp, [
this]() { emit done(
this); }, Qt::QueuedConnection);
329 m_asyncCallback = callback;
330 m_asyncCallbackData = data;
334static QThreadPool *pathWorkThreadPool =
nullptr;
336static void deletePathWorkThreadPool()
338 delete pathWorkThreadPool;
339 pathWorkThreadPool =
nullptr;
345#if !QT_CONFIG(thread)
351 bool didKickOffAsync =
false;
353 for (
int i = 0; i < m_sp.size(); ++i) {
354 ShapePathData &d(m_sp[i]);
358 m_accDirty |= d.syncDirty;
365 d.effectiveDirty |= d.syncDirty;
374 if (d.path.isEmpty()) {
375 d.fillVertices.clear();
376 d.fillIndices.clear();
377 d.strokeVertices.clear();
382 if (async && !pathWorkThreadPool) {
383 qAddPostRoutine(deletePathWorkThreadPool);
384 pathWorkThreadPool =
new QThreadPool;
385 const int idealCount = QThread::idealThreadCount();
386 pathWorkThreadPool->setMaxThreadCount(idealCount > 0 ? idealCount * 2 : 4);
397 const bool supportsElementIndexUint = m_rhiBackendInitialized ? m_supportsElementIndexUint :
true;
399 d.path.setFillRule(d.fillRule);
400 if (m_api == QSGRendererInterface::Unknown)
401 m_api = m_item->window()->rendererInterface()->graphicsApi();
404 r->setAutoDelete(
false);
411 r->triangulationScale = d.triangulationScale;
414 QObject::connect(r, &QQuickShapeFillRunnable::done, qApp, [
this, i](QQuickShapeFillRunnable *r) {
417 if (!r->orphaned && i < m_sp.size()) {
418 ShapePathData &d(m_sp[i]);
419 d.fillVertices = r->fillVertices;
420 d.fillIndices = r->fillIndices;
421 d.indexType = r->indexType;
422 d.pendingFill =
nullptr;
423 d.effectiveDirty |= DirtyFillGeom;
424 maybeUpdateAsyncItem();
428 didKickOffAsync =
true;
432 qtVectorPathForPath(r->path);
433 pathWorkThreadPool->start(r);
436 triangulateFill(d.path, d.fillColor, &d.fillVertices, &d.fillIndices, &d.indexType,
437 supportsElementIndexUint,
438 d.triangulationScale);
443 && (d.strokeColor
.a || d.strokeGradientActive) && d.visible) {
446 r->setAutoDelete(
false);
453 r->clipSize = QSize(m_item->width(), m_item->height());
454 r->triangulationScale = d.triangulationScale;
455 QObject::connect(r, &QQuickShapeStrokeRunnable::done, qApp, [
this, i](QQuickShapeStrokeRunnable *r) {
456 if (!r->orphaned && i < m_sp.size()) {
457 ShapePathData &d(m_sp[i]);
458 d.strokeVertices = r->strokeVertices;
459 d.pendingStroke =
nullptr;
460 d.effectiveDirty |= DirtyStrokeGeom;
461 maybeUpdateAsyncItem();
465 didKickOffAsync =
true;
469 qtVectorPathForPath(r->path);
470 pathWorkThreadPool->start(r);
473 triangulateStroke(d.path, d.pen, d.strokeColor, &d.strokeVertices,
474 QSize(m_item->width(), m_item->height()), d.triangulationScale);
479 if (!didKickOffAsync && async && m_asyncCallback)
480 m_asyncCallback(m_asyncCallbackData);
485 for (
const ShapePathData &d : std::as_const(m_sp)) {
486 if (d.pendingFill || d.pendingStroke)
492 m_asyncCallback(m_asyncCallbackData);
501 QSGGeometry::Type *indexType,
502 bool supportsElementIndexUint,
503 qreal triangulationScale)
505 const QVectorPath &vp = qtVectorPathForPath(path);
507 QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(triangulationScale, triangulationScale), 1, supportsElementIndexUint);
508 const int vertexCount = ts.vertices.size() / 2;
509 fillVertices->resize(vertexCount);
511 const qreal *vsrc = ts.vertices.constData();
512 for (
int i = 0; i < vertexCount; ++i)
513 vdst[i]
.set(vsrc[i * 2] / triangulationScale
, vsrc[i * 2 + 1] / triangulationScale
, fillColor
);
515 size_t indexByteSize;
516 if (ts.indices.type() == QVertexIndexVector::UnsignedShort || vertexCount <= 0xffff) {
517 *indexType = QSGGeometry::UnsignedShortType;
518 const int indexCount = ts.indices.size();
524 fillIndices->resize((indexCount + 1) / 2);
527 if (ts.indices.type() != QVertexIndexVector::UnsignedShort) {
528 quint16 *dst =
reinterpret_cast<quint16 *>(fillIndices->data());
529 const quint32 *src =
reinterpret_cast<
const quint32 *>(ts.indices.data());
530 for (
int i = 0; i < indexCount; ++i)
531 dst[i] = quint16(src[i]);
535 indexByteSize = indexCount *
sizeof(quint16);
537 *indexType = QSGGeometry::UnsignedIntType;
538 fillIndices->resize(ts.indices.size());
539 indexByteSize = ts.indices.size() *
sizeof(quint32);
542 Q_ASSERT(fillIndices->size() *
sizeof(quint32) >= indexByteSize);
543 memcpy(fillIndices->data(), ts.indices.data(), indexByteSize);
550 const QSize &clipSize,
551 qreal triangulationScale)
553 const QVectorPath &vp = qtVectorPathForPath(path);
554 const QRectF clip(QPointF(0, 0), clipSize);
555 const qreal inverseScale = 1.0 / triangulationScale;
557 QTriangulatingStroker stroker;
558 stroker.setInvScale(inverseScale);
560 if (pen.style() == Qt::SolidLine) {
561 stroker.process(vp, pen, clip, {});
563 QDashedStrokeProcessor dashStroker;
564 dashStroker.setInvScale(inverseScale);
565 dashStroker.process(vp, pen, clip, {});
566 QVectorPath dashStroke(dashStroker.points(), dashStroker.elementCount(),
567 dashStroker.elementTypes(), 0);
568 stroker.process(dashStroke, pen, clip, {});
571 if (!stroker.vertexCount()) {
572 strokeVertices->clear();
576 const int vertexCount = stroker.vertexCount() / 2;
577 strokeVertices->resize(vertexCount);
579 const float *vsrc = stroker.vertices();
580 for (
int i = 0; i < vertexCount; ++i)
581 vdst[i]
.set(vsrc[i * 2]
, vsrc[i * 2 + 1]
, strokeColor
);
586 if (m_rootNode != node) {
595 if (!m_rootNode || !m_accDirty)
599 if (!m_rhiBackendInitialized) {
600 auto findRHIBackend = [](QQuickItem *item) -> QRhi * {
601 if (
auto *w = item->window()) {
602 if (
auto *rhi = QQuickWindowPrivate::get(w)->rhi)
607 auto *rhi = findRHIBackend(m_item);
608 if (rhi !=
nullptr) {
609 m_rhiBackendInitialized =
true;
610 m_supportsElementIndexUint = rhi->isFeatureSupported(QRhi::ElementIndexUint);
627 for (ShapePathData &d : m_sp) {
630 *nodePtr =
new QQuickShapeGenericNode;
631 prevNode->m_next = *nodePtr;
632 prevNode->appendChildNode(*nodePtr);
635 QQuickShapeGenericNode *node = *nodePtr;
637 if (m_accDirty & DirtyList) {
638 d.effectiveDirty |= DirtyFillGeom | DirtyStrokeGeom | DirtyColor | DirtyFillGradient
639 | DirtyFillTransform | DirtyFillTexture | DirtyStrokeGradient;
642 if (!d.effectiveDirty) {
644 nodePtr = &node->m_next;
648 if (!d.visible || d.fillColor.a == 0) {
649 delete node->m_fillNode;
650 node->m_fillNode =
nullptr;
651 }
else if (!node->m_fillNode) {
652 node->m_fillNode =
new QQuickShapeGenericStrokeFillNode(m_item->window());
653 if (node->m_strokeNode)
654 node->removeChildNode(node->m_strokeNode);
659 node->insertChildNodeBefore(node->m_fillNode, node->m_next);
661 node->appendChildNode(node->m_fillNode);
662 if (node->m_strokeNode) {
664 node->insertChildNodeBefore(node->m_strokeNode, node->m_next);
666 node->appendChildNode(node->m_strokeNode);
668 d.effectiveDirty |= DirtyFillGeom | DirtyColor | DirtyFillGradient
669 | DirtyFillTransform | DirtyFillTexture;
672 if (!d.visible || d.strokeWidth <= 0.0f || d.strokeColor.a == 0) {
673 delete node->m_strokeNode;
674 node->m_strokeNode =
nullptr;
675 }
else if (!node->m_strokeNode) {
676 node->m_strokeNode =
new QQuickShapeGenericStrokeFillNode(m_item->window());
678 node->insertChildNodeBefore(node->m_strokeNode, node->m_next);
680 node->appendChildNode(node->m_strokeNode);
681 d.effectiveDirty |= DirtyStrokeGeom | DirtyColor | DirtyStrokeGradient;
684 updateFillNode(&d, node);
685 updateStrokeNode(&d, node);
687 d.effectiveDirty = 0;
690 nodePtr = &node->m_next;
693 if (*nodePtr && prevNode) {
694 prevNode->removeChildNode(*nodePtr);
699 if (m_sp.isEmpty()) {
713 if (d->fillGradientActive) {
715 n->m_gradient = d->fillGradient;
719 bool needsUpdate = d->fillTextureProviderItem ==
nullptr && n->m_fillTextureProvider !=
nullptr;
721 && d->fillTextureProviderItem !=
nullptr
722 && n->m_fillTextureProvider != d->fillTextureProviderItem->textureProvider()) {
727 if (n->m_fillTextureProvider !=
nullptr) {
728 QObject::disconnect(n->m_fillTextureProvider, &QSGTextureProvider::textureChanged,
729 n, &QQuickShapeGenericStrokeFillNode::handleTextureChanged);
730 QObject::disconnect(n->m_fillTextureProvider, &QSGTextureProvider::destroyed,
731 n, &QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed);
734 n->m_fillTextureProvider = d->fillTextureProviderItem ==
nullptr
736 : d->fillTextureProviderItem->textureProvider();
738 if (n->m_fillTextureProvider !=
nullptr) {
739 QObject::connect(n->m_fillTextureProvider, &QSGTextureProvider::textureChanged,
740 n, &QQuickShapeGenericStrokeFillNode::handleTextureChanged);
741 QObject::connect(n->m_fillTextureProvider, &QSGTextureProvider::destroyed,
742 n, &QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed);
747 n->m_fillTransform = d->fillTransform;
760 updateShadowDataInNode(d, n);
762 QSGGeometry *g = n->geometry();
763 if (d->fillVertices.isEmpty()) {
764 if (g->vertexCount() || g->indexCount()) {
766 n->markDirty(QSGNode::DirtyGeometry);
771 if (d->fillGradientActive) {
773 switch (d->fillGradientActive) {
780 case ConicalGradient:
784 Q_UNREACHABLE_RETURN();
786 n->activateMaterial(m_item->window(), gradMat);
789 n->markDirty(QSGNode::DirtyMaterial);
794 }
else if (d->fillTextureProviderItem !=
nullptr) {
797 n->markDirty(QSGNode::DirtyMaterial);
801 if ((d->effectiveDirty &
DirtyColor) && !(d->effectiveDirty &
DirtyFillGeom) && d->fillTextureProviderItem ==
nullptr) {
802 ColoredVertex *vdst =
reinterpret_cast<ColoredVertex *>(g->vertexData());
803 for (
int i = 0; i < g->vertexCount(); ++i)
805 n->markDirty(QSGNode::DirtyGeometry);
810 const int indexCount = d->indexType == QSGGeometry::UnsignedShortType
811 ? d->fillIndices.size() * 2 : d->fillIndices.size();
812 if (g->indexType() != d->indexType) {
813 g =
new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(),
814 d->fillVertices.size(), indexCount, d->indexType);
817 g->allocate(d->fillVertices.size(), indexCount);
819 g->setDrawingMode(QSGGeometry::DrawTriangles);
821 memcpy(g->vertexData(), d->fillVertices.constData(), g->vertexCount() * g->sizeOfVertex());
822 memcpy(g->indexData(), d->fillIndices.constData(), g->indexCount() * g->sizeOfIndex());
824 n->markDirty(QSGNode::DirtyGeometry);
835 if (d->strokeGradientActive) {
837 n->m_gradient = d->strokeGradient;
840 QSGGeometry *g = n->geometry();
841 if (d->strokeVertices.isEmpty()) {
842 if (g->vertexCount() || g->indexCount()) {
844 n->markDirty(QSGNode::DirtyGeometry);
849 n->markDirty(QSGNode::DirtyGeometry);
854 if (!g->vertexCount())
855 n->markDirty(QSGNode::DirtyMaterial);
857 if (d->strokeGradientActive) {
859 switch (d->strokeGradientActive) {
866 case ConicalGradient:
870 Q_UNREACHABLE_RETURN();
872 n->activateMaterial(m_item->window(), gradMat);
875 n->markDirty(QSGNode::DirtyMaterial);
883 ColoredVertex *vdst =
reinterpret_cast<ColoredVertex *>(g->vertexData());
884 for (
int i = 0; i < g->vertexCount(); ++i)
890 g->allocate(d->strokeVertices.size(), 0);
891 g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
892 memcpy(g->vertexData(), d->strokeVertices.constData(), g->vertexCount() * g->sizeOfVertex());
897 QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
899 if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
900 return new QSGVertexColorMaterial;
902 qWarning(
"Vertex-color material: Unsupported graphics API %d", api);
909 QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
911 if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
914 qWarning(
"Linear gradient material: Unsupported graphics API %d", api);
921 QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
923 if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
926 qWarning(
"Radial gradient material: Unsupported graphics API %d", api);
933 QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
935 if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
938 qWarning(
"Conical gradient material: Unsupported graphics API %d", api);
945 QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
947 if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
950 qWarning(
"Texture fill material: Unsupported graphics API %d", api);
956 setShaderFileName(VertexStage, QStringLiteral(
":/qt-project.org/shapes/shaders_ng/lineargradient.vert.qsb"), viewCount);
957 setShaderFileName(FragmentStage, QStringLiteral(
":/qt-project.org/shapes/shaders_ng/lineargradient.frag.qsb"), viewCount);
961 QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
963 Q_ASSERT(oldMaterial ==
nullptr || newMaterial->type() == oldMaterial->type());
965 bool changed =
false;
966 QByteArray *buf = state.uniformData();
967 Q_ASSERT(buf->size() >= 84 + 64);
968 const int shaderMatrixCount = newMaterial->viewCount();
969 const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
971 if (state.isMatrixDirty()) {
972 for (
int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
973 const QMatrix4x4 m = state.combinedMatrix();
974 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
981 if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
982 memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
983 m_fillTransform = node->m_fillTransform;
987 if (!oldMaterial || m_gradA.x() != node->m_gradient.a.x() || m_gradA.y() != node->m_gradient.a.y()) {
988 m_gradA = QVector2D(node->m_gradient.a.x(), node->m_gradient.a.y());
989 Q_ASSERT(
sizeof(m_gradA) == 8);
990 memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_gradA, 8);
994 if (!oldMaterial || m_gradB.x() != node->m_gradient.b.x() || m_gradB.y() != node->m_gradient.b.y()) {
995 m_gradB = QVector2D(node->m_gradient.b.x(), node->m_gradient.b.y());
996 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_gradB, 8);
1000 if (state.isOpacityDirty()) {
1001 const float opacity = state.opacity();
1002 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8, &opacity, 4);
1010 QSGMaterial *newMaterial, QSGMaterial *)
1017 const QSGGradientCacheKey cacheKey(node->m_gradient.stops, QGradient::Spread(node->m_gradient.spread));
1018 QSGTexture *t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
1019 t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
1025 static QSGMaterialType type;
1031 Q_ASSERT(other && type() == other->type());
1040 const QSGGradientCache::GradientDesc *ga = &a->m_gradient;
1041 const QSGGradientCache::GradientDesc *gb = &b->m_gradient;
1043 if (
int d = ga->spread - gb->spread)
1046 if (
int d = ga->a.x() - gb->a.x())
1048 if (
int d = ga->a.y() - gb->a.y())
1050 if (
int d = ga->b.x() - gb->b.x())
1052 if (
int d = ga->b.y() - gb->b.y())
1055 if (
int d = ga->stops.size() - gb->stops.size())
1058 for (
int i = 0; i < ga->stops.size(); ++i) {
1059 if (
int d = ga->stops[i].first - gb->stops[i].first)
1061 if (
int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
1065 if (
int d = a->m_fillTransform.compareTo(b->m_fillTransform))
1073 Q_UNUSED(renderMode);
1079 setShaderFileName(VertexStage, QStringLiteral(
":/qt-project.org/shapes/shaders_ng/radialgradient.vert.qsb"), viewCount);
1080 setShaderFileName(FragmentStage, QStringLiteral(
":/qt-project.org/shapes/shaders_ng/radialgradient.frag.qsb"), viewCount);
1084 QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
1086 Q_ASSERT(oldMaterial ==
nullptr || newMaterial->type() == oldMaterial->type());
1088 bool changed =
false;
1089 QByteArray *buf = state.uniformData();
1090 Q_ASSERT(buf->size() >= 92 + 64);
1091 const int shaderMatrixCount = newMaterial->viewCount();
1092 const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
1094 if (state.isMatrixDirty()) {
1095 for (
int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
1096 const QMatrix4x4 m = state.combinedMatrix();
1097 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
1104 if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
1105 memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
1106 m_fillTransform = node->m_fillTransform;
1110 const QPointF centerPoint = node->m_gradient.a;
1111 const QPointF focalPoint = node->m_gradient.b;
1112 const QPointF focalToCenter = centerPoint - focalPoint;
1113 const float centerRadius = node->m_gradient.v0;
1114 const float focalRadius = node->m_gradient.v1;
1116 if (!oldMaterial || m_focalPoint.x() != focalPoint.x() || m_focalPoint.y() != focalPoint.y()) {
1117 m_focalPoint = QVector2D(focalPoint.x(), focalPoint.y());
1118 Q_ASSERT(
sizeof(m_focalPoint) == 8);
1119 memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_focalPoint, 8);
1123 if (!oldMaterial || m_focalToCenter.x() != focalToCenter.x() || m_focalToCenter.y() != focalToCenter.y()) {
1124 m_focalToCenter = QVector2D(focalToCenter.x(), focalToCenter.y());
1125 Q_ASSERT(
sizeof(m_focalToCenter) == 8);
1126 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_focalToCenter, 8);
1130 if (!oldMaterial || m_centerRadius != centerRadius) {
1131 m_centerRadius = centerRadius;
1132 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8, &m_centerRadius, 4);
1136 if (!oldMaterial || m_focalRadius != focalRadius) {
1137 m_focalRadius = focalRadius;
1138 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8 + 4, &m_focalRadius, 4);
1142 if (state.isOpacityDirty()) {
1143 const float opacity = state.opacity();
1144 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8 + 4 + 4, &opacity, 4);
1152 QSGMaterial *newMaterial, QSGMaterial *)
1159 const QSGGradientCacheKey cacheKey(node->m_gradient.stops, QGradient::Spread(node->m_gradient.spread));
1160 QSGTexture *t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
1161 t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
1167 static QSGMaterialType type;
1173 Q_ASSERT(other && type() == other->type());
1182 const QSGGradientCache::GradientDesc *ga = &a->m_gradient;
1183 const QSGGradientCache::GradientDesc *gb = &b->m_gradient;
1185 if (
int d = ga->spread - gb->spread)
1188 if (
int d = ga->a.x() - gb->a.x())
1190 if (
int d = ga->a.y() - gb->a.y())
1192 if (
int d = ga->b.x() - gb->b.x())
1194 if (
int d = ga->b.y() - gb->b.y())
1197 if (
int d = ga->v0 - gb->v0)
1199 if (
int d = ga->v1 - gb->v1)
1202 if (
int d = ga->stops.size() - gb->stops.size())
1205 for (
int i = 0; i < ga->stops.size(); ++i) {
1206 if (
int d = ga->stops[i].first - gb->stops[i].first)
1208 if (
int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
1212 if (
int d = a->m_fillTransform.compareTo(b->m_fillTransform))
1220 Q_UNUSED(renderMode);
1226 setShaderFileName(VertexStage, QStringLiteral(
":/qt-project.org/shapes/shaders_ng/conicalgradient.vert.qsb"), viewCount);
1227 setShaderFileName(FragmentStage, QStringLiteral(
":/qt-project.org/shapes/shaders_ng/conicalgradient.frag.qsb"), viewCount);
1231 QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
1233 Q_ASSERT(oldMaterial ==
nullptr || newMaterial->type() == oldMaterial->type());
1235 bool changed =
false;
1236 QByteArray *buf = state.uniformData();
1237 Q_ASSERT(buf->size() >= 80 + 64);
1238 const int shaderMatrixCount = newMaterial->viewCount();
1239 const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
1241 if (state.isMatrixDirty()) {
1242 for (
int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
1243 const QMatrix4x4 m = state.combinedMatrix();
1244 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
1251 if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
1252 memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
1253 m_fillTransform = node->m_fillTransform;
1257 const QPointF centerPoint = node->m_gradient.a;
1258 const float angle = -qDegreesToRadians(node->m_gradient.v0);
1260 if (!oldMaterial || m_centerPoint.x() != centerPoint.x() || m_centerPoint.y() != centerPoint.y()) {
1261 m_centerPoint = QVector2D(centerPoint.x(), centerPoint.y());
1262 Q_ASSERT(
sizeof(m_centerPoint) == 8);
1263 memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_centerPoint, 8);
1267 if (!oldMaterial || m_angle != angle) {
1269 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_angle, 4);
1273 if (state.isOpacityDirty()) {
1274 const float opacity = state.opacity();
1275 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 4, &opacity, 4);
1283 QSGMaterial *newMaterial, QSGMaterial *)
1290 const QSGGradientCacheKey cacheKey(node->m_gradient.stops, QGradient::Spread(node->m_gradient.spread));
1291 QSGTexture *t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
1292 t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
1298 static QSGMaterialType type;
1304 Q_ASSERT(other && type() == other->type());
1313 const QSGGradientCache::GradientDesc *ga = &a->m_gradient;
1314 const QSGGradientCache::GradientDesc *gb = &b->m_gradient;
1316 if (
int d = ga->a.x() - gb->a.x())
1318 if (
int d = ga->a.y() - gb->a.y())
1321 if (
int d = ga->v0 - gb->v0)
1324 if (
int d = ga->stops.size() - gb->stops.size())
1327 for (
int i = 0; i < ga->stops.size(); ++i) {
1328 if (
int d = ga->stops[i].first - gb->stops[i].first)
1330 if (
int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
1334 if (
int d = a->m_fillTransform.compareTo(b->m_fillTransform))
1342 Q_UNUSED(renderMode);
1348 setShaderFileName(VertexStage, QStringLiteral(
":/qt-project.org/shapes/shaders_ng/texturefill.vert.qsb"), viewCount);
1349 setShaderFileName(FragmentStage, QStringLiteral(
":/qt-project.org/shapes/shaders_ng/texturefill.frag.qsb"), viewCount);
1353 QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
1355 Q_ASSERT(oldMaterial ==
nullptr || newMaterial->type() == oldMaterial->type());
1357 bool changed =
false;
1358 QByteArray *buf = state.uniformData();
1359 const int shaderMatrixCount = newMaterial->viewCount();
1360 const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
1361 Q_ASSERT(buf->size() >= 64 * shaderMatrixCount + 64 + 8 + 4);
1363 if (state.isMatrixDirty()) {
1364 for (
int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
1365 const QMatrix4x4 m = state.combinedMatrix();
1366 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
1373 if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
1374 memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
1375 m_fillTransform = node->m_fillTransform;
1379 const QSizeF boundsSize = node->m_fillTextureProvider !=
nullptr && node->m_fillTextureProvider->texture() !=
nullptr
1380 ? node->m_fillTextureProvider->texture()->textureSize()
1384 const QVector2D boundsVector(boundsSize.width() / state.devicePixelRatio(),
1385 boundsSize.height() / state.devicePixelRatio());
1386 if (!oldMaterial || m_boundsSize != boundsVector) {
1387 m_boundsSize = boundsVector;
1388 Q_ASSERT(
sizeof(m_boundsSize) == 8);
1389 memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_boundsSize, 8);
1393 if (state.isOpacityDirty()) {
1394 const float opacity = state.opacity();
1395 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &opacity, 4);
1403 QSGMaterial *newMaterial, QSGMaterial *)
1410 if (node->m_fillTextureProvider !=
nullptr) {
1411 QSGTexture *providedTexture = node->m_fillTextureProvider->texture();
1412 if (providedTexture !=
nullptr) {
1413 if (providedTexture->isAtlasTexture()) {
1417 QSGTexture *newTexture = providedTexture->removedFromAtlas(state.resourceUpdateBatch());
1418 if (newTexture !=
nullptr)
1419 providedTexture = newTexture;
1422 providedTexture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
1423 *texture = providedTexture;
1428 if (m->dummyTexture() ==
nullptr) {
1429 QSGPlainTexture *dummyTexture =
new QSGPlainTexture;
1430 dummyTexture->setFiltering(QSGTexture::Nearest);
1431 dummyTexture->setHorizontalWrapMode(QSGTexture::Repeat);
1432 dummyTexture->setVerticalWrapMode(QSGTexture::Repeat);
1433 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
1435 dummyTexture->setImage(img);
1436 dummyTexture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
1438 m->setDummyTexture(dummyTexture);
1441 *texture = m->dummyTexture();
1446 delete m_dummyTexture;
1451 static QSGMaterialType type;
1457 Q_ASSERT(other && type() == other->type());
1466 if (
int d = a->m_fillTransform.compareTo(b->m_fillTransform))
1469 const qintptr diff = qintptr(a->m_fillTextureProvider) - qintptr(b->m_fillTextureProvider);
1470 return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
1475 Q_UNUSED(renderMode);
1481#include "moc_qquickshapegenericrenderer_p.cpp"
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
QQuickShapeConicalGradientMaterial(QQuickShapeGenericStrokeFillNode *node)
int compare(const QSGMaterial *other) const override
Compares this material to other and returns 0 if they are equal; -1 if this material should sort befo...
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
QQuickShapeGenericStrokeFillNode * node() const
void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to prepare use of sampled images in the shader,...
bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
QQuickShapeConicalGradientRhiShader(int viewCount)
bool supportsElementIndexUint
QQuickShapeGenericRenderer::Color4ub fillColor
QQuickShapeGenericRenderer::VertexContainerType fillVertices
QQuickShapeGenericRenderer::IndexContainerType fillIndices
QQuickShapeGenericStrokeFillNode * m_fillNode
QQuickShapeGenericStrokeFillNode * m_strokeNode
QQuickShapeGenericNode * m_next
void setAsyncCallback(void(*)(void *), void *) override
void setFillGradient(int index, QQuickShapeGradient *gradient) override
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, qreal dashOffset, const QList< qreal > &dashPattern) override
void setFillTransform(int index, const QSGTransform &transform) override
QList< quint32 > IndexContainerType
void setCosmeticStroke(int index, bool c) override
void setStrokeGradient(int index, QQuickShapeGradient *gradient) override
QList< QSGGeometry::ColoredPoint2D > VertexContainerType
void setPath(int index, const QPainterPath &path, QQuickShapePath::PathHints pathHints={}) override
void setStrokeColor(int index, const QColor &color) override
void setFillRule(int index, QQuickShapePath::FillRule fillRule) override
void setFillTextureProvider(int index, QQuickItem *textureProviderItem) override
void setFillColor(int index, const QColor &color) override
void setTriangulationScale(int index, qreal scale) override
void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override
void setStrokeWidth(int index, qreal w) override
~QQuickShapeGenericRenderer()
void setRootNode(QQuickShapeGenericNode *node)
void handleSceneChange(QQuickWindow *window) override
void beginSync(int totalCount, bool *countChanged) override
void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override
void updateNode() override
void setVisible(int index, bool visible) override
void endSync(bool async) override
void preprocess() override
Override this function to do processing on the node before it is rendered.
void activateMaterial(QQuickWindow *window, Material m)
QQuickShapeLinearGradientMaterial(QQuickShapeGenericStrokeFillNode *node)
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
int compare(const QSGMaterial *other) const override
Compares this material to other and returns 0 if they are equal; -1 if this material should sort befo...
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
QQuickShapeGenericStrokeFillNode * node() const
void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to prepare use of sampled images in the shader,...
QQuickShapeLinearGradientRhiShader(int viewCount)
bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
QQuickShapeGenericStrokeFillNode * node() const
QQuickShapeRadialGradientMaterial(QQuickShapeGenericStrokeFillNode *node)
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
int compare(const QSGMaterial *other) const override
Compares this material to other and returns 0 if they are equal; -1 if this material should sort befo...
bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
QQuickShapeRadialGradientRhiShader(int viewCount)
void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to prepare use of sampled images in the shader,...
QQuickShapeGenericRenderer::Color4ub strokeColor
QQuickShapeGenericRenderer::VertexContainerType strokeVertices
QQuickShapeTextureFillMaterial(QQuickShapeGenericStrokeFillNode *node)
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
int compare(const QSGMaterial *other) const override
Compares this material to other and returns 0 if they are equal; -1 if this material should sort befo...
QQuickShapeGenericStrokeFillNode * node() const
~QQuickShapeTextureFillMaterial() override
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
QQuickShapeTextureFillRhiShader(int viewCount)
bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to prepare use of sampled images in the shader,...
Combined button and popup list for selecting options.
static QQuickShapeGenericRenderer::Color4ub colorToColor4ub(const QColor &c)
static QQuickAbstractPathRenderer::FillGradientType copyGenericGradient(const QQuickShapeGradient *gradient, QSGGradientCache::GradientDesc *dst)
#define QSG_RUNTIME_DESCRIPTION
void set(float nx, float ny, QQuickShapeGenericRenderer::Color4ub ncolor)