Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickshapegenericrenderer.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include <QtGui/private/qtriangulator_p.h>
6#include <QtGui/private/qtriangulatingstroker_p.h>
7#include <rhi/qrhi.h>
8#include <QSGVertexColorMaterial>
9
10#include <QtQuick/private/qsggradientcache_p.h>
11
12#if QT_CONFIG(thread)
13#include <QThreadPool>
14#endif
15
17
18struct ColoredVertex // must match QSGGeometry::ColoredPoint2D
19{
20 float x, y;
22 void set(float nx, float ny, QQuickShapeGenericRenderer::Color4ub ncolor)
23 {
24 x = nx; y = ny; color = ncolor;
25 }
26};
27
29{
30 float r, g, b, a;
31 c.getRgbF(&r, &g, &b, &a);
33 uchar(qRound(r * a * 255)),
34 uchar(qRound(g * a * 255)),
35 uchar(qRound(b * a * 255)),
36 uchar(qRound(a * 255))
37 };
38 return color;
39}
40
51
53{
54 switch (m) {
55 case MatSolidColor:
56 // Use vertexcolor material. Items with different colors remain batchable
57 // this way, at the expense of having to provide per-vertex color values.
59 break;
62 break;
65 break;
68 break;
69 default:
70 qWarning("Unknown material %d", m);
71 return;
72 }
73
74 if (material() != m_material.data())
75 setMaterial(m_material.data());
76}
77
79{
80 for (ShapePathData &d : m_sp) {
81 if (d.pendingFill)
82 d.pendingFill->orphaned = true;
83 if (d.pendingStroke)
84 d.pendingStroke->orphaned = true;
85 }
86}
87
88// sync, and so triangulation too, happens on the gui thread
89// - except when async is set, in which case triangulation is moved to worker threads
90
91void QQuickShapeGenericRenderer::beginSync(int totalCount, bool *countChanged)
92{
93 if (m_sp.size() != totalCount) {
94 m_sp.resize(totalCount);
95 m_accDirty |= DirtyList;
96 *countChanged = true;
97 } else {
98 *countChanged = false;
99 }
100 for (ShapePathData &d : m_sp)
101 d.syncDirty = 0;
102}
103
105{
106 ShapePathData &d(m_sp[index]);
107 d.path = path ? path->path() : QPainterPath();
108 d.syncDirty |= DirtyFillGeom | DirtyStrokeGeom;
109}
110
112{
113 ShapePathData &d(m_sp[index]);
114 const bool wasTransparent = d.strokeColor.a == 0;
115 d.strokeColor = colorToColor4ub(color);
116 const bool isTransparent = d.strokeColor.a == 0;
117 d.syncDirty |= DirtyColor;
118 if (wasTransparent && !isTransparent)
119 d.syncDirty |= DirtyStrokeGeom;
120}
121
123{
124 ShapePathData &d(m_sp[index]);
125 d.strokeWidth = w;
126 if (w >= 0.0f)
127 d.pen.setWidthF(w);
128 d.syncDirty |= DirtyStrokeGeom;
129}
130
132{
133 ShapePathData &d(m_sp[index]);
134 const bool wasTransparent = d.fillColor.a == 0;
135 d.fillColor = colorToColor4ub(color);
136 const bool isTransparent = d.fillColor.a == 0;
137 d.syncDirty |= DirtyColor;
138 if (wasTransparent && !isTransparent)
139 d.syncDirty |= DirtyFillGeom;
140}
141
143{
144 ShapePathData &d(m_sp[index]);
145 d.fillRule = Qt::FillRule(fillRule);
146 d.syncDirty |= DirtyFillGeom;
147}
148
150{
151 ShapePathData &d(m_sp[index]);
152 d.pen.setJoinStyle(Qt::PenJoinStyle(joinStyle));
153 d.pen.setMiterLimit(miterLimit);
154 d.syncDirty |= DirtyStrokeGeom;
155}
156
158{
159 ShapePathData &d(m_sp[index]);
160 d.pen.setCapStyle(Qt::PenCapStyle(capStyle));
161 d.syncDirty |= DirtyStrokeGeom;
162}
163
165 qreal dashOffset, const QVector<qreal> &dashPattern)
166{
167 ShapePathData &d(m_sp[index]);
168 d.pen.setStyle(Qt::PenStyle(strokeStyle));
169 if (strokeStyle == QQuickShapePath::DashLine) {
170 d.pen.setDashPattern(dashPattern);
171 d.pen.setDashOffset(dashOffset);
172 }
173 d.syncDirty |= DirtyStrokeGeom;
174}
175
177{
178 ShapePathData &d(m_sp[index]);
179 if (gradient) {
180 d.fillGradient.stops = gradient->gradientStops(); // sorted
181 d.fillGradient.spread = QGradient::Spread(gradient->spread());
182 if (QQuickShapeLinearGradient *g = qobject_cast<QQuickShapeLinearGradient *>(gradient)) {
183 d.fillGradientActive = LinearGradient;
184 d.fillGradient.a = QPointF(g->x1(), g->y1());
185 d.fillGradient.b = QPointF(g->x2(), g->y2());
186 } else if (QQuickShapeRadialGradient *g = qobject_cast<QQuickShapeRadialGradient *>(gradient)) {
187 d.fillGradientActive = RadialGradient;
188 d.fillGradient.a = QPointF(g->centerX(), g->centerY());
189 d.fillGradient.b = QPointF(g->focalX(), g->focalY());
190 d.fillGradient.v0 = g->centerRadius();
191 d.fillGradient.v1 = g->focalRadius();
192 } else if (QQuickShapeConicalGradient *g = qobject_cast<QQuickShapeConicalGradient *>(gradient)) {
193 d.fillGradientActive = ConicalGradient;
194 d.fillGradient.a = QPointF(g->centerX(), g->centerY());
195 d.fillGradient.v0 = g->angle();
196 } else {
197 Q_UNREACHABLE();
198 }
199 } else {
200 d.fillGradientActive = NoGradient;
201 }
202 d.syncDirty |= DirtyFillGradient;
203}
204
206{
207 ShapePathData &d(m_sp[index]);
208 d.fillTransform = transform;
209 d.syncDirty |= DirtyFillTransform;
210}
211
213{
214 // No dirty, this is called at the start of every sync. Just store the value.
215 m_triangulationScale = scale;
216}
217
224
230
231void QQuickShapeGenericRenderer::setAsyncCallback(void (*callback)(void *), void *data)
232{
233 m_asyncCallback = callback;
234 m_asyncCallbackData = data;
235}
236
237#if QT_CONFIG(thread)
238static QThreadPool *pathWorkThreadPool = nullptr;
239
240static void deletePathWorkThreadPool()
241{
242 delete pathWorkThreadPool;
243 pathWorkThreadPool = nullptr;
244}
245#endif
246
248{
249#if !QT_CONFIG(thread)
250 // Force synchronous mode for the no-thread configuration due
251 // to lack of QThreadPool.
252 async = false;
253#endif
254
255 bool didKickOffAsync = false;
256
257 for (int i = 0; i < m_sp.size(); ++i) {
258 ShapePathData &d(m_sp[i]);
259 if (!d.syncDirty)
260 continue;
261
262 m_accDirty |= d.syncDirty;
263
264 // Use a shadow dirty flag in order to avoid losing state in case there are
265 // multiple syncs with different dirty flags before we get to updateNode()
266 // on the render thread (with the gui thread blocked). For our purposes
267 // here syncDirty is still required since geometry regeneration must only
268 // happen when there was an actual change in this particular sync round.
269 d.effectiveDirty |= d.syncDirty;
270
271 if (d.path.isEmpty()) {
272 d.fillVertices.clear();
273 d.fillIndices.clear();
274 d.strokeVertices.clear();
275 continue;
276 }
277
278#if QT_CONFIG(thread)
279 if (async && !pathWorkThreadPool) {
280 qAddPostRoutine(deletePathWorkThreadPool);
281 pathWorkThreadPool = new QThreadPool;
282 const int idealCount = QThread::idealThreadCount();
283 pathWorkThreadPool->setMaxThreadCount(idealCount > 0 ? idealCount * 2 : 4);
284 }
285#endif
286 auto testFeatureIndexUint = [](QQuickItem *item) -> bool {
287 if (auto *w = item->window()) {
288 if (auto *rhi = QQuickWindowPrivate::get(w)->rhi)
289 return rhi->isFeatureSupported(QRhi::ElementIndexUint);
290 }
291 return true;
292 };
293 static bool supportsElementIndexUint = testFeatureIndexUint(m_item);
294 if ((d.syncDirty & DirtyFillGeom) && d.fillColor.a) {
295 d.path.setFillRule(d.fillRule);
297 m_api = m_item->window()->rendererInterface()->graphicsApi();
298 if (async) {
300 r->setAutoDelete(false);
301 if (d.pendingFill)
302 d.pendingFill->orphaned = true;
303 d.pendingFill = r;
304 r->path = d.path;
305 r->fillColor = d.fillColor;
306 r->supportsElementIndexUint = supportsElementIndexUint;
307 r->triangulationScale = m_triangulationScale;
308 // Unlikely in practice but in theory m_sp could be
309 // resized. Therefore, capture 'i' instead of 'd'.
311 // Bail out when orphaned (meaning either another run was
312 // started after this one, or the renderer got destroyed).
313 if (!r->orphaned && i < m_sp.size()) {
314 ShapePathData &d(m_sp[i]);
315 d.fillVertices = r->fillVertices;
316 d.fillIndices = r->fillIndices;
317 d.indexType = r->indexType;
318 d.pendingFill = nullptr;
319 d.effectiveDirty |= DirtyFillGeom;
320 maybeUpdateAsyncItem();
321 }
322 r->deleteLater();
323 });
324 didKickOffAsync = true;
325#if QT_CONFIG(thread)
326 // qtVectorPathForPath() initializes a unique_ptr without locking.
327 // Do that before starting the threads as otherwise we get a race condition.
328 qtVectorPathForPath(r->path);
329 pathWorkThreadPool->start(r);
330#endif
331 } else {
332 triangulateFill(d.path, d.fillColor, &d.fillVertices, &d.fillIndices, &d.indexType,
333 supportsElementIndexUint,
334 m_triangulationScale);
335 }
336 }
337
338 if ((d.syncDirty & DirtyStrokeGeom) && d.strokeWidth >= 0.0f && d.strokeColor.a) {
339 if (async) {
341 r->setAutoDelete(false);
342 if (d.pendingStroke)
343 d.pendingStroke->orphaned = true;
344 d.pendingStroke = r;
345 r->path = d.path;
346 r->pen = d.pen;
347 r->strokeColor = d.strokeColor;
348 r->clipSize = QSize(m_item->width(), m_item->height());
349 r->triangulationScale = m_triangulationScale;
351 if (!r->orphaned && i < m_sp.size()) {
352 ShapePathData &d(m_sp[i]);
353 d.strokeVertices = r->strokeVertices;
354 d.pendingStroke = nullptr;
355 d.effectiveDirty |= DirtyStrokeGeom;
356 maybeUpdateAsyncItem();
357 }
358 r->deleteLater();
359 });
360 didKickOffAsync = true;
361#if QT_CONFIG(thread)
362 // qtVectorPathForPath() initializes a unique_ptr without locking.
363 // Do that before starting the threads as otherwise we get a race condition.
364 qtVectorPathForPath(r->path);
365 pathWorkThreadPool->start(r);
366#endif
367 } else {
368 triangulateStroke(d.path, d.pen, d.strokeColor, &d.strokeVertices,
369 QSize(m_item->width(), m_item->height()), m_triangulationScale);
370 }
371 }
372 }
373
374 if (!didKickOffAsync && async && m_asyncCallback)
375 m_asyncCallback(m_asyncCallbackData);
376}
377
378void QQuickShapeGenericRenderer::maybeUpdateAsyncItem()
379{
380 for (const ShapePathData &d : std::as_const(m_sp)) {
381 if (d.pendingFill || d.pendingStroke)
382 return;
383 }
384 m_accDirty |= DirtyFillGeom | DirtyStrokeGeom;
385 m_item->update();
386 if (m_asyncCallback)
387 m_asyncCallback(m_asyncCallbackData);
388}
389
390// the stroke/fill triangulation functions may be invoked either on the gui
391// thread or some worker thread and must thus be self-contained.
393 const Color4ub &fillColor,
394 VertexContainerType *fillVertices,
395 IndexContainerType *fillIndices,
396 QSGGeometry::Type *indexType,
397 bool supportsElementIndexUint,
398 qreal triangulationScale)
399{
401
402 QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(triangulationScale, triangulationScale), 1, supportsElementIndexUint);
403 const int vertexCount = ts.vertices.size() / 2; // just a qreal vector with x,y hence the / 2
404 fillVertices->resize(vertexCount);
405 ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(fillVertices->data());
406 const qreal *vsrc = ts.vertices.constData();
407 for (int i = 0; i < vertexCount; ++i)
408 vdst[i].set(vsrc[i * 2] / triangulationScale, vsrc[i * 2 + 1] / triangulationScale, fillColor);
409
410 size_t indexByteSize;
413 // fillIndices is still QVector<quint32>. Just resize to N/2 and pack
414 // the N quint16s into it.
415 fillIndices->resize(ts.indices.size() / 2);
416 indexByteSize = ts.indices.size() * sizeof(quint16);
417 } else {
418 *indexType = QSGGeometry::UnsignedIntType;
419 fillIndices->resize(ts.indices.size());
420 indexByteSize = ts.indices.size() * sizeof(quint32);
421 }
422 memcpy(fillIndices->data(), ts.indices.data(), indexByteSize);
423}
424
426 const QPen &pen,
427 const Color4ub &strokeColor,
428 VertexContainerType *strokeVertices,
429 const QSize &clipSize,
430 qreal triangulationScale)
431{
433 const QRectF clip(QPointF(0, 0), clipSize);
434 const qreal inverseScale = 1.0 / triangulationScale;
435
436 QTriangulatingStroker stroker;
437 stroker.setInvScale(inverseScale);
438
439 if (pen.style() == Qt::SolidLine) {
440 stroker.process(vp, pen, clip, {});
441 } else {
442 QDashedStrokeProcessor dashStroker;
443 dashStroker.setInvScale(inverseScale);
444 dashStroker.process(vp, pen, clip, {});
445 QVectorPath dashStroke(dashStroker.points(), dashStroker.elementCount(),
446 dashStroker.elementTypes(), 0);
447 stroker.process(dashStroke, pen, clip, {});
448 }
449
450 if (!stroker.vertexCount()) {
451 strokeVertices->clear();
452 return;
453 }
454
455 const int vertexCount = stroker.vertexCount() / 2; // just a float vector with x,y hence the / 2
456 strokeVertices->resize(vertexCount);
457 ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(strokeVertices->data());
458 const float *vsrc = stroker.vertices();
459 for (int i = 0; i < vertexCount; ++i)
460 vdst[i].set(vsrc[i * 2], vsrc[i * 2 + 1], strokeColor);
461}
462
464{
465 if (m_rootNode != node) {
466 m_rootNode = node;
467 m_accDirty |= DirtyList;
468 }
469}
470
471// on the render thread with gui blocked
473{
474 if (!m_rootNode || !m_accDirty)
475 return;
476
477// [ m_rootNode ]
478// / / /
479// #0 [ fill ] [ stroke ] [ next ]
480// / / |
481// #1 [ fill ] [ stroke ] [ next ]
482// / / |
483// #2 [ fill ] [ stroke ] [ next ]
484// ...
485// ...
486
487 QQuickShapeGenericNode **nodePtr = &m_rootNode;
488 QQuickShapeGenericNode *prevNode = nullptr;
489
490 for (ShapePathData &d : m_sp) {
491 if (!*nodePtr) {
492 Q_ASSERT(prevNode);
493 *nodePtr = new QQuickShapeGenericNode;
494 prevNode->m_next = *nodePtr;
495 prevNode->appendChildNode(*nodePtr);
496 }
497
498 QQuickShapeGenericNode *node = *nodePtr;
499
500 if (m_accDirty & DirtyList)
502
503 if (!d.effectiveDirty) {
504 prevNode = node;
505 nodePtr = &node->m_next;
506 continue;
507 }
508
509 if (d.fillColor.a == 0) {
510 delete node->m_fillNode;
511 node->m_fillNode = nullptr;
512 } else if (!node->m_fillNode) {
514 if (node->m_strokeNode)
515 node->removeChildNode(node->m_strokeNode);
516 node->appendChildNode(node->m_fillNode);
517 if (node->m_strokeNode)
518 node->appendChildNode(node->m_strokeNode);
519 d.effectiveDirty |= DirtyFillGeom;
520 }
521
522 if (d.strokeWidth < 0.0f || d.strokeColor.a == 0) {
523 delete node->m_strokeNode;
524 node->m_strokeNode = nullptr;
525 } else if (!node->m_strokeNode) {
527 node->appendChildNode(node->m_strokeNode);
528 d.effectiveDirty |= DirtyStrokeGeom;
529 }
530
531 updateFillNode(&d, node);
532 updateStrokeNode(&d, node);
533
534 d.effectiveDirty = 0;
535
536 prevNode = node;
537 nodePtr = &node->m_next;
538 }
539
540 if (*nodePtr && prevNode) {
541 prevNode->removeChildNode(*nodePtr);
542 delete *nodePtr;
543 *nodePtr = nullptr;
544 }
545
546 m_accDirty = 0;
547}
548
549void QQuickShapeGenericRenderer::updateShadowDataInNode(ShapePathData *d, QQuickShapeGenericStrokeFillNode *n)
550{
551 if (d->fillGradientActive) {
552 if (d->effectiveDirty & DirtyFillGradient)
553 n->m_fillGradient = d->fillGradient;
554 if (d->effectiveDirty & DirtyFillTransform)
555 n->m_fillTransform = d->fillTransform;
556 }
557}
558
559void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node)
560{
561 if (!node->m_fillNode)
562 return;
563 if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient | DirtyFillTransform)))
564 return;
565
566 // Make a copy of the data that will be accessed by the material on
567 // the render thread. This must be done even when we bail out below.
569 updateShadowDataInNode(d, n);
570
571 QSGGeometry *g = n->geometry();
572 if (d->fillVertices.isEmpty()) {
573 if (g->vertexCount() || g->indexCount()) {
574 g->allocate(0, 0);
575 n->markDirty(QSGNode::DirtyGeometry);
576 }
577 return;
578 }
579
580 if (d->fillGradientActive) {
582 switch (d->fillGradientActive) {
583 case LinearGradient:
585 break;
586 case RadialGradient:
588 break;
589 case ConicalGradient:
591 break;
592 default:
593 Q_UNREACHABLE_RETURN();
594 }
595 n->activateMaterial(m_item->window(), gradMat);
596 if (d->effectiveDirty & (DirtyFillGradient | DirtyFillTransform)) {
597 // Gradients are implemented via a texture-based material.
598 n->markDirty(QSGNode::DirtyMaterial);
599 // stop here if only the gradient or filltransform changed; no need to touch the geometry
600 if (!(d->effectiveDirty & DirtyFillGeom))
601 return;
602 }
603 } else {
604 n->activateMaterial(m_item->window(), QQuickShapeGenericStrokeFillNode::MatSolidColor);
605 // fast path for updating only color values when no change in vertex positions
606 if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom)) {
607 ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
608 for (int i = 0; i < g->vertexCount(); ++i)
609 vdst[i].set(vdst[i].x, vdst[i].y, d->fillColor);
610 n->markDirty(QSGNode::DirtyGeometry);
611 return;
612 }
613 }
614
615 const int indexCount = d->indexType == QSGGeometry::UnsignedShortType
616 ? d->fillIndices.size() * 2 : d->fillIndices.size();
617 if (g->indexType() != d->indexType) {
619 d->fillVertices.size(), indexCount, d->indexType);
620 n->setGeometry(g);
621 } else {
622 g->allocate(d->fillVertices.size(), indexCount);
623 }
624 g->setDrawingMode(QSGGeometry::DrawTriangles);
625 memcpy(g->vertexData(), d->fillVertices.constData(), g->vertexCount() * g->sizeOfVertex());
626 memcpy(g->indexData(), d->fillIndices.constData(), g->indexCount() * g->sizeOfIndex());
627
628 n->markDirty(QSGNode::DirtyGeometry);
629}
630
631void QQuickShapeGenericRenderer::updateStrokeNode(ShapePathData *d, QQuickShapeGenericNode *node)
632{
633 if (!node->m_strokeNode)
634 return;
635 if (!(d->effectiveDirty & (DirtyStrokeGeom | DirtyColor)))
636 return;
637
639 QSGGeometry *g = n->geometry();
640 if (d->strokeVertices.isEmpty()) {
641 if (g->vertexCount() || g->indexCount()) {
642 g->allocate(0, 0);
643 n->markDirty(QSGNode::DirtyGeometry);
644 }
645 return;
646 }
647
648 n->markDirty(QSGNode::DirtyGeometry);
649
650 // Async loading runs update once, bails out above, then updates again once
651 // ready. Set the material dirty then. This is in-line with fill where the
652 // first activateMaterial() achieves the same.
653 if (!g->vertexCount())
654 n->markDirty(QSGNode::DirtyMaterial);
655
656 if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyStrokeGeom)) {
657 ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
658 for (int i = 0; i < g->vertexCount(); ++i)
659 vdst[i].set(vdst[i].x, vdst[i].y, d->strokeColor);
660 return;
661 }
662
663 g->allocate(d->strokeVertices.size(), 0);
664 g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
665 memcpy(g->vertexData(), d->strokeVertices.constData(), g->vertexCount() * g->sizeOfVertex());
666}
667
669{
670 QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
671
673 return new QSGVertexColorMaterial;
674
675 qWarning("Vertex-color material: Unsupported graphics API %d", api);
676 return nullptr;
677}
678
681{
682 QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
683
685 return new QQuickShapeLinearGradientMaterial(node);
686
687 qWarning("Linear gradient material: Unsupported graphics API %d", api);
688 return nullptr;
689}
690
693{
694 QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
695
697 return new QQuickShapeRadialGradientMaterial(node);
698
699 qWarning("Radial gradient material: Unsupported graphics API %d", api);
700 return nullptr;
701}
702
705{
706 QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
707
709 return new QQuickShapeConicalGradientMaterial(node);
710
711 qWarning("Conical gradient material: Unsupported graphics API %d", api);
712 return nullptr;
713}
714
716{
717 setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/lineargradient.vert.qsb"), viewCount);
718 setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/lineargradient.frag.qsb"), viewCount);
719}
720
722 QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
723{
724 Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
726 bool changed = false;
727 QByteArray *buf = state.uniformData();
728 Q_ASSERT(buf->size() >= 84 + 64);
729 const int shaderMatrixCount = newMaterial->viewCount();
730 const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
731
732 if (state.isMatrixDirty()) {
733 for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
734 const QMatrix4x4 m = state.combinedMatrix();
735 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
736 changed = true;
737 }
738 }
739
740 QQuickShapeGenericStrokeFillNode *node = m->node();
741
742 if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
743 memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
744 m_fillTransform = node->m_fillTransform;
745 changed = true;
746 }
747
748 if (!oldMaterial || m_gradA.x() != node->m_fillGradient.a.x() || m_gradA.y() != node->m_fillGradient.a.y()) {
749 m_gradA = QVector2D(node->m_fillGradient.a.x(), node->m_fillGradient.a.y());
750 Q_ASSERT(sizeof(m_gradA) == 8);
751 memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_gradA, 8);
752 changed = true;
753 }
754
755 if (!oldMaterial || m_gradB.x() != node->m_fillGradient.b.x() || m_gradB.y() != node->m_fillGradient.b.y()) {
756 m_gradB = QVector2D(node->m_fillGradient.b.x(), node->m_fillGradient.b.y());
757 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_gradB, 8);
758 changed = true;
759 }
760
761 if (state.isOpacityDirty()) {
762 const float opacity = state.opacity();
763 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8, &opacity, 4);
764 changed = true;
765 }
766
767 return changed;
768}
769
771 QSGMaterial *newMaterial, QSGMaterial *)
772{
773 if (binding != 1)
774 return;
775
777 QQuickShapeGenericStrokeFillNode *node = m->node();
780 t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
781 *texture = t;
782}
783
789
791{
792 Q_ASSERT(other && type() == other->type());
794
797 Q_ASSERT(a && b);
798 if (a == b)
799 return 0;
800
801 const QSGGradientCache::GradientDesc *ga = &a->m_fillGradient;
802 const QSGGradientCache::GradientDesc *gb = &b->m_fillGradient;
803
804 if (int d = ga->spread - gb->spread)
805 return d;
806
807 if (int d = ga->a.x() - gb->a.x())
808 return d;
809 if (int d = ga->a.y() - gb->a.y())
810 return d;
811 if (int d = ga->b.x() - gb->b.x())
812 return d;
813 if (int d = ga->b.y() - gb->b.y())
814 return d;
815
816 if (int d = ga->stops.size() - gb->stops.size())
817 return d;
818
819 for (int i = 0; i < ga->stops.size(); ++i) {
820 if (int d = ga->stops[i].first - gb->stops[i].first)
821 return d;
822 if (int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
823 return d;
824 }
825
826 if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
827 return d;
828
829 return 0;
830}
831
837
839{
840 setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/radialgradient.vert.qsb"), viewCount);
841 setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/radialgradient.frag.qsb"), viewCount);
842}
843
845 QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
846{
847 Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
849 bool changed = false;
850 QByteArray *buf = state.uniformData();
851 Q_ASSERT(buf->size() >= 92 + 64);
852 const int shaderMatrixCount = newMaterial->viewCount();
853 const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
854
855 if (state.isMatrixDirty()) {
856 for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
857 const QMatrix4x4 m = state.combinedMatrix();
858 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
859 changed = true;
860 }
861 }
862
863 QQuickShapeGenericStrokeFillNode *node = m->node();
864
865 if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
866 memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
867 m_fillTransform = node->m_fillTransform;
868 changed = true;
869 }
870
871 const QPointF centerPoint = node->m_fillGradient.a;
872 const QPointF focalPoint = node->m_fillGradient.b;
873 const QPointF focalToCenter = centerPoint - focalPoint;
874 const float centerRadius = node->m_fillGradient.v0;
875 const float focalRadius = node->m_fillGradient.v1;
876
877 if (!oldMaterial || m_focalPoint.x() != focalPoint.x() || m_focalPoint.y() != focalPoint.y()) {
878 m_focalPoint = QVector2D(focalPoint.x(), focalPoint.y());
879 Q_ASSERT(sizeof(m_focalPoint) == 8);
880 memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_focalPoint, 8);
881 changed = true;
882 }
883
884 if (!oldMaterial || m_focalToCenter.x() != focalToCenter.x() || m_focalToCenter.y() != focalToCenter.y()) {
885 m_focalToCenter = QVector2D(focalToCenter.x(), focalToCenter.y());
886 Q_ASSERT(sizeof(m_focalToCenter) == 8);
887 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_focalToCenter, 8);
888 changed = true;
889 }
890
891 if (!oldMaterial || m_centerRadius != centerRadius) {
892 m_centerRadius = centerRadius;
893 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8, &m_centerRadius, 4);
894 changed = true;
895 }
896
897 if (!oldMaterial || m_focalRadius != focalRadius) {
898 m_focalRadius = focalRadius;
899 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8 + 4, &m_focalRadius, 4);
900 changed = true;
901 }
902
903 if (state.isOpacityDirty()) {
904 const float opacity = state.opacity();
905 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8 + 4 + 4, &opacity, 4);
906 changed = true;
907 }
908
909 return changed;
910}
911
913 QSGMaterial *newMaterial, QSGMaterial *)
914{
915 if (binding != 1)
916 return;
917
919 QQuickShapeGenericStrokeFillNode *node = m->node();
922 t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
923 *texture = t;
924}
925
931
933{
934 Q_ASSERT(other && type() == other->type());
936
939 Q_ASSERT(a && b);
940 if (a == b)
941 return 0;
942
943 const QSGGradientCache::GradientDesc *ga = &a->m_fillGradient;
944 const QSGGradientCache::GradientDesc *gb = &b->m_fillGradient;
945
946 if (int d = ga->spread - gb->spread)
947 return d;
948
949 if (int d = ga->a.x() - gb->a.x())
950 return d;
951 if (int d = ga->a.y() - gb->a.y())
952 return d;
953 if (int d = ga->b.x() - gb->b.x())
954 return d;
955 if (int d = ga->b.y() - gb->b.y())
956 return d;
957
958 if (int d = ga->v0 - gb->v0)
959 return d;
960 if (int d = ga->v1 - gb->v1)
961 return d;
962
963 if (int d = ga->stops.size() - gb->stops.size())
964 return d;
965
966 for (int i = 0; i < ga->stops.size(); ++i) {
967 if (int d = ga->stops[i].first - gb->stops[i].first)
968 return d;
969 if (int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
970 return d;
971 }
972
973 if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
974 return d;
975
976 return 0;
977}
978
984
986{
987 setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/conicalgradient.vert.qsb"), viewCount);
988 setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/conicalgradient.frag.qsb"), viewCount);
989}
990
992 QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
993{
994 Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
996 bool changed = false;
997 QByteArray *buf = state.uniformData();
998 Q_ASSERT(buf->size() >= 80 + 64);
999 const int shaderMatrixCount = newMaterial->viewCount();
1000 const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
1001
1002 if (state.isMatrixDirty()) {
1003 for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
1004 const QMatrix4x4 m = state.combinedMatrix();
1005 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
1006 changed = true;
1007 }
1008 }
1009
1010 QQuickShapeGenericStrokeFillNode *node = m->node();
1011
1012 if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
1013 memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
1014 m_fillTransform = node->m_fillTransform;
1015 changed = true;
1016 }
1017
1018 const QPointF centerPoint = node->m_fillGradient.a;
1019 const float angle = -qDegreesToRadians(node->m_fillGradient.v0);
1020
1021 if (!oldMaterial || m_centerPoint.x() != centerPoint.x() || m_centerPoint.y() != centerPoint.y()) {
1022 m_centerPoint = QVector2D(centerPoint.x(), centerPoint.y());
1023 Q_ASSERT(sizeof(m_centerPoint) == 8);
1024 memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_centerPoint, 8);
1025 changed = true;
1026 }
1027
1028 if (!oldMaterial || m_angle != angle) {
1029 m_angle = angle;
1030 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_angle, 4);
1031 changed = true;
1032 }
1033
1034 if (state.isOpacityDirty()) {
1035 const float opacity = state.opacity();
1036 memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 4, &opacity, 4);
1037 changed = true;
1038 }
1039
1040 return changed;
1041}
1042
1044 QSGMaterial *newMaterial, QSGMaterial *)
1045{
1046 if (binding != 1)
1047 return;
1048
1050 QQuickShapeGenericStrokeFillNode *node = m->node();
1053 t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
1054 *texture = t;
1055}
1056
1062
1064{
1065 Q_ASSERT(other && type() == other->type());
1067
1070 Q_ASSERT(a && b);
1071 if (a == b)
1072 return 0;
1073
1074 const QSGGradientCache::GradientDesc *ga = &a->m_fillGradient;
1075 const QSGGradientCache::GradientDesc *gb = &b->m_fillGradient;
1076
1077 if (int d = ga->a.x() - gb->a.x())
1078 return d;
1079 if (int d = ga->a.y() - gb->a.y())
1080 return d;
1081
1082 if (int d = ga->v0 - gb->v0)
1083 return d;
1084
1085 if (int d = ga->stops.size() - gb->stops.size())
1086 return d;
1087
1088 for (int i = 0; i < ga->stops.size(); ++i) {
1089 if (int d = ga->stops[i].first - gb->stops[i].first)
1090 return d;
1091 if (int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
1092 return d;
1093 }
1094
1095 if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
1096 return d;
1097
1098 return 0;
1099}
1100
1106
1108
1109#include "moc_qquickshapegenericrenderer_p.cpp"
\inmodule QtCore
Definition qbytearray.h:57
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
QPainterPath::ElementType * elementTypes() const
void process(const QVectorPath &path, const QPen &pen, const QRectF &clip, QPainter::RenderHints hints)
void setInvScale(qreal invScale)
Spread
Specifies how the area outside the gradient area should be filled.
Definition qbrush.h:146
QGraphicsWidget * window() const
Definition qlist.h:75
qsizetype size() const noexcept
Definition qlist.h:397
const_pointer constData() const noexcept
Definition qlist.h:433
pointer data()
Definition qlist.h:431
void resize(qsizetype size)
Definition qlist.h:403
void clear()
Definition qlist.h:434
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
\inmodule QtGui
\inmodule QtGui
Definition qpen.h:28
Qt::PenStyle style() const
Returns the pen style.
Definition qpen.cpp:366
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
QGradientStops gradientStops() const
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
QQuickWindow * window() const
Returns the window in which this item is rendered.
qreal width
This property holds the width of this item.
Definition qquickitem.h:75
qreal height
This property holds the height of this item.
Definition qquickitem.h:76
void update()
Schedules a call to updatePaintNode() for this item.
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
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...
QQuickShapeGenericRenderer::Color4ub fillColor
QQuickShapeGenericRenderer::VertexContainerType fillVertices
QQuickShapeGenericRenderer::IndexContainerType fillIndices
void done(QQuickShapeFillRunnable *self)
void run() override
Implement this pure virtual function in your subclass.
static QSGMaterial * createLinearGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node)
static QSGMaterial * createConicalGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node)
static QSGMaterial * createVertexColor(QQuickWindow *window)
static QSGMaterial * createRadialGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node)
QQuickShapeGenericStrokeFillNode * m_fillNode
QQuickShapeGenericStrokeFillNode * m_strokeNode
void setAsyncCallback(void(*)(void *), void *) override
void setTriangulationScale(qreal scale) override
void setFillGradient(int index, QQuickShapeGradient *gradient) override
void setFillTransform(int index, const QSGTransform &transform) override
static void triangulateFill(const QPainterPath &path, const Color4ub &fillColor, VertexContainerType *fillVertices, IndexContainerType *fillIndices, QSGGeometry::Type *indexType, bool supportsElementIndexUint, qreal triangulationScale)
void setStrokeColor(int index, const QColor &color) override
void setFillRule(int index, QQuickShapePath::FillRule fillRule) override
void setFillColor(int index, const QColor &color) override
void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override
void setStrokeWidth(int index, qreal w) override
void setRootNode(QQuickShapeGenericNode *node)
void beginSync(int totalCount, bool *countChanged) override
void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override
static void triangulateStroke(const QPainterPath &path, const QPen &pen, const Color4ub &strokeColor, VertexContainerType *strokeVertices, const QSize &clipSize, qreal triangulationScale)
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, qreal dashOffset, const QVector< qreal > &dashPattern) override
void setPath(int index, const QQuickPath *path) override
QSGGradientCache::GradientDesc m_fillGradient
void activateMaterial(QQuickWindow *window, Material m)
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,...
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
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...
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
void done(QQuickShapeStrokeRunnable *self)
void run() override
Implement this pure virtual function in your subclass.
static QQuickWindowPrivate * get(QQuickWindow *c)
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtCore\reentrant
Definition qrect.h:484
@ ElementIndexUint
Definition qrhi.h:1843
void setAutoDelete(bool autoDelete)
Enables auto-deletion if autoDelete is true; otherwise auto-deletion is disabled.
Definition qrunnable.h:38
void setGeometry(QSGGeometry *geometry)
Sets the geometry of this node to geometry.
Definition qsgnode.cpp:764
QSGMaterial * material() const
Returns the material of the QSGGeometryNode.
Definition qsgnode.h:194
void setMaterial(QSGMaterial *material)
Sets the material of this geometry node to material.
Definition qsgnode.cpp:927
The QSGGeometry class provides low-level storage for graphics primitives in the \l{Qt Quick Scene Gra...
Definition qsggeometry.h:15
static const AttributeSet & defaultAttributes_ColoredPoint2D()
Convenience function which returns attributes to be used for per vertex colored 2D drawing.
void allocate(int vertexCount, int indexCount=0)
Resizes the vertex and index data of this geometry object to fit vertexCount vertices and indexCount ...
Type
Specifies the component type in the vertex data.
Definition qsggeometry.h:43
static QSGGradientCache * cacheForRhi(QRhi *rhi)
Encapsulates the current rendering state during a call to QSGMaterialShader::updateUniformData() and ...
The QSGMaterialShader class represents a graphics API independent shader program.
void setShaderFileName(Stage stage, const QString &filename)
Sets the filename for the shader for the specified stage.
The QSGMaterial class encapsulates rendering state for a shader program.
Definition qsgmaterial.h:15
int viewCount() const
void removeChildNode(QSGNode *node)
Removes node from this node's list of children.
Definition qsgnode.cpp:500
@ DirtyMaterial
Definition qsgnode.h:75
@ DirtyGeometry
Definition qsgnode.h:74
@ OwnsGeometry
Definition qsgnode.h:57
void appendChildNode(QSGNode *node)
Appends node to this node's list of children.
Definition qsgnode.cpp:398
void setFlag(Flag, bool=true)
Sets the flag f on this node if enabled is true; otherwise clears the flag.
Definition qsgnode.cpp:586
RenderMode
\value RenderMode2D Normal 2D rendering \value RenderMode2DNoDepthBuffer Normal 2D rendering with dep...
static bool isApiRhiBased(GraphicsApi api)
virtual GraphicsApi graphicsApi() const =0
Returns the graphics API that is in use by the Qt Quick scenegraph.
GraphicsApi
\value Unknown An unknown graphics API is in use \value Software The Qt Quick 2D Renderer is in use \...
\inmodule QtQuick
Definition qsgtexture.h:20
const float * invertedData() const
The QSGVertexColorMaterial class provides a convenient way of rendering per-vertex colored geometry i...
T * data() const noexcept
Returns the value of the pointer referenced by this object.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\inmodule QtCore
Definition qsize.h:25
\inmodule QtCore
Definition qthreadpool.h:22
static int idealThreadCount() noexcept
Definition qthread.cpp:1049
static QTransform fromScale(qreal dx, qreal dy)
Creates a matrix which corresponds to a scaling of sx horizontally and sy vertically.
const float * vertices() const
void setInvScale(qreal invScale)
void process(const QVectorPath &path, const QPen &pen, const QRectF &clip, QPainter::RenderHints hints)
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
constexpr float y() const noexcept
Returns the y coordinate of this point.
Definition qvectornd.h:502
constexpr float x() const noexcept
Returns the x coordinate of this point.
Definition qvectornd.h:501
const void * data() const
else opt state
[0]
Combined button and popup list for selecting options.
@ SolidLine
PenJoinStyle
PenCapStyle
void qAddPostRoutine(QtCleanUpFunction p)
#define qApp
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
static QByteArray cacheKey(Args &&...args)
#define qWarning
Definition qlogging.h:166
constexpr float qDegreesToRadians(float degrees)
Definition qmath.h:260
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
const GLfloat * m
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLboolean r
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint GLuint focalPoint
GLuint color
[2]
GLfloat angle
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLuint texture
GLboolean GLboolean g
GLfloat n
GLint y
GLuint GLenum GLenum transform
GLbyte nx
const GLubyte * c
GLfixed ny
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLenum GLenum GLenum GLenum GLenum scale
const QVectorPath & qtVectorPathForPath(const QPainterPath &path)
static QQuickShapeGenericRenderer::Color4ub colorToColor4ub(const QColor &c)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
void qsgnode_set_description(QSGNode *node, const QString &description)
Definition qsgnode.cpp:641
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define emit
#define Q_UNUSED(x)
Q_GUI_EXPORT QTriangleSet qTriangulate(const qreal *polygon, int count, uint hint, const QTransform &matrix, bool allowUintIndices)
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
unsigned short quint16
Definition qtypes.h:48
double qreal
Definition qtypes.h:187
QFuture< QSet< QChar > > set
[10]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
QGraphicsItem * item
aWidget window() -> setWindowTitle("New Window Title")
[2]
QNetworkRequestFactory api
[0]
void set(float nx, float ny, QQuickShapeGenericRenderer::Color4ub ncolor)
QQuickShapeGenericRenderer::Color4ub color
The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
QList< qreal > vertices
QVertexIndexVector indices