8#include <QtCore/qthreadpool.h>
11#include <QtGui/qvector2d.h>
12#include <QtGui/qvector4d.h>
13#include <QtGui/private/qtriangulator_p.h>
14#include <QtGui/private/qtriangulatingstroker_p.h>
15#include <QtGui/private/qrhi_p.h>
17#include <QtQuick/private/qsgcurvefillnode_p.h>
18#include <QtQuick/private/qsgcurvestrokenode_p.h>
19#include <QtQuick/private/qquadpath_p.h>
20#include <QtQuick/private/qsgcurveprocessor_p.h>
21#include <QtQuick/qsgmaterial.h>
32 QQuickShapeWireFrameMaterialShader(
int viewCount)
34 setShaderFileName(VertexStage,
35 QStringLiteral(
":/qt-project.org/shapes/shaders_ng/wireframe.vert.qsb"), viewCount);
36 setShaderFileName(FragmentStage,
37 QStringLiteral(
":/qt-project.org/shapes/shaders_ng/wireframe.frag.qsb"), viewCount);
45 const int matrixCount =
qMin(
state.projectionMatrixCount(), newMaterial->viewCount());
47 for (
int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
48 if (
state.isMatrixDirty()) {
50 memcpy(
buf->data() + 64 * viewIndex,
m.constData(), 64);
59class QQuickShapeWireFrameMaterial :
public QSGMaterial
62 QQuickShapeWireFrameMaterial()
64 setFlag(Blending,
true);
80 return new QQuickShapeWireFrameMaterialShader(viewCount());
88 struct WireFrameVertex
93 QQuickShapeWireFrameNode()
95 setFlag(OwnsGeometry,
true);
105 void activateMaterial()
107 m_material.reset(
new QQuickShapeWireFrameMaterial);
108 setMaterial(m_material.data());
121 void cookGeometry()
override
127 QScopedPointer<QQuickShapeWireFrameMaterial> m_material;
133 for (
const PathData &pd : std::as_const(m_paths)) {
134 if (pd.currentRunner)
135 pd.currentRunner->orphaned =
true;
141 if (countChanged !=
nullptr && totalCount != m_paths.size())
142 *countChanged =
true;
143 m_paths.resize(totalCount);
148 constexpr QQuickShapePath::PathHints noHints;
149 const auto *shapePath = qobject_cast<const QQuickShapePath *>(
path);
155 auto &pathData = m_paths[
index];
156 pathData.originalPath =
path;
157 pathData.pathHints = pathHints;
163 auto &pathData = m_paths[
index];
164 const bool wasVisible = pathData.isStrokeVisible();
165 pathData.pen.setColor(
color);
166 if (pathData.isStrokeVisible() != wasVisible)
174 auto &pathData = m_paths[
index];
176 pathData.validPenWidth =
true;
177 pathData.pen.setWidthF(
w);
179 pathData.validPenWidth =
false;
186 auto &pathData = m_paths[
index];
187 const bool wasVisible = pathData.isFillVisible();
188 pathData.fillColor =
color;
189 if (pathData.isFillVisible() != wasVisible)
197 auto &pathData = m_paths[
index];
206 auto &pathData = m_paths[
index];
208 pathData.pen.setMiterLimit(miterLimit);
214 auto &pathData = m_paths[
index];
222 const QVector<qreal> &dashPattern)
224 auto &pathData = m_paths[
index];
227 pathData.pen.setDashPattern(dashPattern);
228 pathData.pen.setDashOffset(dashOffset);
235 PathData &pd(m_paths[
index]);
245 pd.gradient.
a =
QPointF(
g->centerX(),
g->centerY());
246 pd.gradient.
b =
QPointF(
g->focalX(),
g->focalY());
247 pd.gradient.
v0 =
g->centerRadius();
248 pd.gradient.
v1 =
g->focalRadius();
251 pd.gradient.
a =
QPointF(
g->centerX(),
g->centerY());
252 pd.gradient.
v0 =
g->angle();
254 if (gradient !=
nullptr) {
255 static bool warned =
false;
258 qCWarning(lcShapeCurveRenderer) <<
"Unsupported gradient fill";
272 auto &pathData = m_paths[
index];
279 m_asyncCallback = callback;
280 m_asyncCallbackData =
data;
285 bool didKickOffAsync =
false;
287 for (PathData &pathData : m_paths) {
288 if (!pathData.m_dirty)
296 if (pathData.currentRunner) {
302 createRunner(&pathData);
306 pathData.currentRunner->isAsync =
true;
308 didKickOffAsync =
true;
312 pathData.currentRunner->run();
316 if (async && !didKickOffAsync && m_asyncCallback)
317 m_asyncCallback(m_asyncCallbackData);
320void QQuickShapeCurveRenderer::createRunner(PathData *pathData)
324 runner->setAutoDelete(
false);
325 runner->pathData = *pathData;
326 runner->pathData.fillNodes.clear();
327 runner->pathData.strokeNodes.clear();
328 runner->pathData.currentRunner =
nullptr;
330 pathData->currentRunner = runner;
331 pathData->m_dirty = 0;
337 }
else if (
r->isAsync) {
338 maybeUpdateAsyncItem();
343void QQuickShapeCurveRenderer::maybeUpdateAsyncItem()
345 for (
const PathData &pd :
std::as_const(m_paths)) {
346 if (pd.currentRunner && !pd.currentRunner->isDone)
352 m_asyncCallback(m_asyncCallbackData);
357 QQuickShapeCurveRenderer::processPath(&
pathData);
366 auto updateUniforms = [](
const PathData &pathData) {
367 for (
auto &pathNode : std::as_const(pathData.fillNodes))
368 pathNode->setColor(pathData.fillColor);
369 for (
auto &strokeNode : std::as_const(pathData.strokeNodes))
370 strokeNode->setColor(pathData.pen.color());
375 for (
int i = 0;
i < m_paths.size();
i++) {
376 PathData &pathData = m_paths[
i];
377 if (pathData.currentRunner) {
378 if (!pathData.currentRunner->
isDone)
381 QSGNode *nextNode = pathData.strokeNodes.value(0);
383 for (
int j =
i + 1; !nextNode &&
j < m_paths.size();
j++) {
384 const PathData &pd = m_paths[
j];
385 nextNode = pd.fillNodes.isEmpty() ? pd.strokeNodes.value(0) : pd.fillNodes.value(0);
388 const PathData &newData = pathData.currentRunner->
pathData;
390 pathData.path = newData.path;
392 pathData.fillPath = newData.fillPath;
393 for (
auto *node : std::as_const(newData.fillNodes)) {
399 toBeDeleted += pathData.fillNodes;
400 pathData.fillNodes = newData.fillNodes;
403 for (
auto *node : std::as_const(newData.strokeNodes)) {
409 toBeDeleted += pathData.strokeNodes;
410 pathData.strokeNodes = newData.strokeNodes;
414 updateUniforms(pathData);
420 pathData.currentRunner =
nullptr;
425 updateUniforms(pathData);
426 pathData.m_dirty = 0;
432void QQuickShapeCurveRenderer::processPath(PathData *pathData)
439 int &dirtyFlags = pathData->m_dirty;
446 pathData->path.setFillRule(pathData->fillRule);
447 pathData->fillPath = {};
452 if (pathData->isFillVisible()) {
453 if (pathData->fillPath.isEmpty()) {
454 pathData->fillPath = pathData->path.subPathsClosed();
455 if (doIntersetionSolving)
457 pathData->fillPath.addCurvatureData();
458 if (doOverlapSolving)
461 pathData->fillNodes = addFillNodes(*pathData);
467 if (pathData->isStrokeVisible()) {
468 const QPen &pen = pathData->pen;
470 pathData->strokePath = pathData->path;
474 if (useTriangulatingStroker)
475 pathData->strokeNodes = addTriangulatingStrokerNodes(*pathData);
477 pathData->strokeNodes = addCurveStrokeNodes(*pathData);
486 const qsizetype approxDataCount = 20 * pathData.fillPath.elementCount();
487 node->reserve(approxDataCount);
492 internalHull.
setFillRule(pathData.fillPath.fillRule());
495 const float dbg = visualizeDebug ? 0.5f : 0.0f;
498 QVector<QQuickShapeWireFrameNode::WireFrameVertex> wfVertices;
499 wfVertices.reserve(approxDataCount);
503 [&wfVertices, &node](
const std::array<QVector2D, 3> &
v,
504 const std::array<QVector2D, 3> &
n,
507 node->appendTriangle(v, n, uvForPoint);
509 wfVertices.append({v.at(0).x(), v.at(0).y(), 1.0f, 0.0f, 0.0f});
510 wfVertices.append({
v.at(1).
x(),
v.at(1).y(), 0.0f, 1.0f, 0.0f});
511 wfVertices.append({
v.at(2).
x(),
v.at(2).y(), 0.0f, 0.0f, 1.0f});
514 QVector<quint32>
indices = node->uncookedIndexes();
516 node->setColor(
color);
517 node->setFillTransform(pathData.fillTransform);
518 node->setFillGradient(pathData.gradient);
520 node->cookGeometry();
524 const bool wireFrame = debugVisualization() & DebugWireframe;
526 QQuickShapeWireFrameNode *wfNode =
new QQuickShapeWireFrameNode;
531 wfNode->setGeometry(wfg);
534 memcpy(wfg->indexData(),
536 indices.size() * wfg->sizeOfIndex());
537 memcpy(wfg->vertexData(),
539 wfg->vertexCount() * wfg->sizeOfVertex());
552 QVector<QQuickShapeWireFrameNode::WireFrameVertex> wfVertices;
555 const auto painterPath = pathData.strokePath.toPainterPath();
557 QPen pen = pathData.pen;
558 stroker.
process(vp, pen, {}, {});
579 return uvForPoint(
v1,
v2,
p - p0);
584 QVector2D baseLine = endPoint - startPoint;
585 QVector2D insideVector = referencePoint - startPoint;
590 return swap ? startPoint + normal : startPoint - normal;
596 if (
p1 ==
p2 ||
p2 == p3) {
601 auto uv = curveUv(
p1,
p2, p3,
p);
605 node->appendTriangle(
p1,
p2, p3, uvForPoint);
608 wfVertices.append({
p1.x(),
p1.y(), 1.0f, 0.0f, 0.0f});
609 wfVertices.append({
p2.x(),
p2.y(), 0.0f, 0.1f, 0.0f});
610 wfVertices.append({p3.x(), p3.y(), 0.0f, 0.0f, 1.0f});
612 if (!disableExtraTriangles) {
616 node->appendTriangle(
p1, op, p3, uvForPoint);
618 wfVertices.append({
p1.x(),
p1.y(), 1.0f, 0.0f, 0.0f});
619 wfVertices.append({op.
x(), op.
y(), 0.0f, 1.0f, 0.0f});
620 wfVertices.append({p3.x(), p3.y(), 0.0f, 0.0f, 1.0f});
625 const float *verts = stroker.
vertices();
626 for (
int i = 0;
i < vertCount - 2; ++
i) {
628 for (
int j = 0;
j < 3; ++
j) {
632 addStrokeTriangle(
p[0],
p[1],
p[2], isOdd);
635 QVector<quint32>
indices = node->uncookedIndexes();
637 node->setColor(
color);
638 node->setFillGradient(pathData.gradient);
640 node->cookGeometry();
645 QQuickShapeWireFrameNode *wfNode =
new QQuickShapeWireFrameNode;
650 wfNode->setGeometry(wfg);
653 memcpy(wfg->indexData(),
655 indices.size() * wfg->sizeOfIndex());
656 memcpy(wfg->vertexData(),
658 wfg->vertexCount() * wfg->sizeOfVertex());
676 return debugVisualizationFlags | envFlags;
681 if (debugVisualizationFlags == options)
683 debugVisualizationFlags = options;
694 QVector<QQuickShapeWireFrameNode::WireFrameVertex> wfVertices;
696 const float miterLimit = pathData.pen.miterLimit();
697 const float penWidth = pathData.pen.widthF();
704 pathData.pen.joinStyle(),
705 pathData.pen.capStyle(),
706 [&wfVertices, &node](
const std::array<QVector2D, 3> &
s,
707 const std::array<QVector2D, 3> &
p,
708 const std::array<QVector2D, 3> &
n,
711 const QVector2D &p0 = s.at(0);
712 const QVector2D &p1 = s.at(1);
713 const QVector2D &p2 = s.at(2);
715 node->appendTriangle(s, std::array<QVector2D, 2>{p.at(0), p.at(2)},
n);
717 node->appendTriangle(
s,
p,
n);
719 wfVertices.append({p0.x(), p0.y(), 1.0f, 0.0f, 0.0f});
720 wfVertices.append({
p1.x(),
p1.y(), 0.0f, 1.0f, 0.0f});
721 wfVertices.append({
p2.x(),
p2.y(), 0.0f, 0.0f, 1.0f});
725 auto indexCopy = node->uncookedIndexes();
727 node->setColor(
color);
728 node->setStrokeWidth(pathData.pen.widthF());
729 node->cookGeometry();
732 const bool wireFrame = debugVisualization() & DebugWireframe;
734 QQuickShapeWireFrameNode *wfNode =
new QQuickShapeWireFrameNode;
740 wfNode->setGeometry(wfg);
743 memcpy(wfg->indexData(),
745 indexCopy.size() * wfg->sizeOfIndex());
746 memcpy(wfg->vertexData(),
748 wfg->vertexCount() * wfg->sizeOfVertex());
The QColor class provides colors based on RGB, HSV or CMYK values.
Spread
Specifies how the area outside the gradient area should be filled.
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void deleteLater()
\threadsafe
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule of the painter path to the given fillRule.
qreal widthF() const
Returns the pen width with floating point precision.
QList< qreal > dashPattern() const
Returns the dash pattern of this pen.
qreal dashOffset() const
Returns the dash offset for the pen.
Qt::PenStyle style() const
Returns the pen style.
\inmodule QtCore\reentrant
@ PathNonOverlappingControlPointTriangles
static QQuadPath fromPainterPath(const QPainterPath &path, PathHints hints={})
QGradientStops gradientStops() const
void update()
Schedules a call to updatePaintNode() for this item.
QVector< QSGCurveAbstractNode * > NodeList
void beginSync(int totalCount, bool *countChanged) override
static int debugVisualization()
void setRootNode(QSGNode *node)
static void setDebugVisualization(int options)
void setFillGradient(int index, QQuickShapeGradient *gradient) override
void endSync(bool async) override
void setStrokeWidth(int index, qreal w) override
friend class QQuickShapeCurveRunnable
void updateNode() override
void setFillTransform(int index, const QSGTransform &transform) override
void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override
~QQuickShapeCurveRenderer() override
void setStrokeColor(int index, const QColor &color) override
void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override
void setFillColor(int index, const QColor &color) override
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, qreal dashOffset, const QVector< qreal > &dashPattern) override
void setPath(int index, const QQuickPath *path) override
void setAsyncCallback(void(*)(void *), void *) override
void setFillRule(int index, QQuickShapePath::FillRule fillRule) override
QQuickShapeCurveRenderer::PathData pathData
void done(QQuickShapeCurveRunnable *self)
void run() override
Implement this pure virtual function in your subclass.
void setGradientType(QGradient::Type type)
static void processStroke(const QQuadPath &strokePath, float miterLimit, float penWidth, Qt::PenJoinStyle joinStyle, Qt::PenCapStyle capStyle, addStrokeTriangleCallback addTriangle, int subdivisions=3)
std::function< QVector3D(QVector2D)> uvForPointCallback
static bool solveOverlaps(QQuadPath &path)
static bool solveIntersections(QQuadPath &path, bool removeNestedPaths=true)
static void processFill(const QQuadPath &path, Qt::FillRule fillRule, addTriangleCallback addTriangle)
void setDebug(float newDebug)
The QSGGeometry class provides low-level storage for graphics primitives in the \l{Qt Quick Scene Gra...
The QSGMaterialShader class represents a graphics API independent shader program.
The QSGMaterial class encapsulates rendering state for a shader program.
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
void appendChildNode(QSGNode *node)
Appends node to this node's list of children.
void insertChildNodeBefore(QSGNode *node, QSGNode *before)
Inserts node to this node's list of children before the node specified with before.
RenderMode
\value RenderMode2D Normal 2D rendering \value RenderMode2DNoDepthBuffer Normal 2D rendering with dep...
int toInt(bool *ok=nullptr, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
static QThreadPool * globalInstance()
Returns the global QThreadPool instance.
const float * vertices() const
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.
constexpr float y() const noexcept
Returns the y coordinate of this point.
constexpr float x() const noexcept
Returns the x coordinate of this point.
static constexpr float dotProduct(QVector2D v1, QVector2D v2) noexcept
Returns the dot product of v1 and v2.
The QVector3D class represents a vector or vertex in 3D space.
qDeleteAll(list.begin(), list.end())
Combined button and popup list for selecting options.
void updateUniformData(QByteArray *dst, const QVideoFrameFormat &format, const QVideoFrame &frame, const QMatrix4x4 &transform, float opacity, float maxNits)
static struct AttrInfo attrs[]
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
constexpr const T & qMin(const T &a, const T &b)
GLint GLfloat GLfloat GLfloat v2
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLenum GLsizei const GLchar * buf
GLsizei GLenum const void * indices
GLuint GLenum GLenum transform
GLsizei const GLchar *const * path
const QVectorPath & qtVectorPathForPath(const QPainterPath &path)
static bool isLine(const QBezier &bezier)
#define QStringLiteral(str)
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
static int compare(quint64 a, quint64 b)
if(qFloatDistance(a, b)<(1<< 7))
[0]
myFilter setColor(QColor(128, 0, 0))
The QSGGeometry::AttributeSet describes how the vertices in a QSGGeometry are built up.
The QSGGeometry::Attribute describes a single vertex attribute in a QSGGeometry.
static Attribute createWithAttributeType(int pos, int tupleSize, int primitiveType, AttributeType attributeType)
Creates a new QSGGeometry::Attribute for attribute register pos with tupleSize.
The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.