From b6cd4a23d7e80bf09ca17389f9d74e7c42842449 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 24 Sep 2024 12:17:22 +0200 Subject: [PATCH 1/6] bad check fixed --- playground/gradients/GradientQuickShape.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/gradients/GradientQuickShape.cpp b/playground/gradients/GradientQuickShape.cpp index 9ace9733..cfe00b13 100644 --- a/playground/gradients/GradientQuickShape.cpp +++ b/playground/gradients/GradientQuickShape.cpp @@ -57,7 +57,7 @@ namespace auto effectiveGradient = gradient.effectiveGradient(); effectiveGradient.stretchTo( rect ); - switch( static_cast< int >( gradient.type() ) ) + switch( static_cast< int >( effectiveGradient.type() ) ) { case QskGradient::Linear: { From a989ff92c9ad0f0e16fdedb31ccf7e19f9b59e3e Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 24 Sep 2024 12:20:03 +0200 Subject: [PATCH 2/6] resolving QskGradient::Stops depends on the shape and can't be resolved in QskFillNode. --- src/nodes/QskArcRenderNode.cpp | 13 +++++++++++-- src/nodes/QskArcRenderer.cpp | 4 +++- src/nodes/QskFillNode.cpp | 27 +++++++++++++++++++-------- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/nodes/QskArcRenderNode.cpp b/src/nodes/QskArcRenderNode.cpp index 2abacb58..ff2f8fa4 100644 --- a/src/nodes/QskArcRenderNode.cpp +++ b/src/nodes/QskArcRenderNode.cpp @@ -104,8 +104,17 @@ void QskArcRenderNode::updateFilling( const QRectF& rect, return; } - const bool coloredGeometry = hasHint( PreferColoredGeometry ) - && QskArcRenderer::isGradientSupported( rect, metrics, gradient ); + bool coloredGeometry = hasHint( PreferColoredGeometry ); + if ( coloredGeometry ) + { + // not all gradients are supported by the renderer + coloredGeometry = QskArcRenderer::isGradientSupported( rect, metrics, gradient ); + } + else + { + // QskGradient::Stops is specific for QskArcRenderer + coloredGeometry = ( gradient.type() == QskGradient::Stops ); + } bool dirtyGeometry = d->updateMetrics( rect, metrics, radial, borderWidth ); bool dirtyMaterial = d->updateColors( QColor(), gradient ); diff --git a/src/nodes/QskArcRenderer.cpp b/src/nodes/QskArcRenderer.cpp index 48cd0f0e..02e843f9 100644 --- a/src/nodes/QskArcRenderer.cpp +++ b/src/nodes/QskArcRenderer.cpp @@ -458,6 +458,7 @@ bool QskArcRenderer::isGradientSupported( const QRectF& rect, } case QskGradient::Conic: { +#if 0 const auto direction = gradient.conicDirection(); if ( direction.center() == rect.center() ) { @@ -470,6 +471,7 @@ bool QskArcRenderer::isGradientSupported( const QRectF& rect, */ } } +#endif return false; } @@ -572,7 +574,7 @@ void QskArcRenderer::setBorderLines( const QRectF& rect, return; } - const Renderer renderer( rect, metrics, radial, QskGradient(), 0 ); + const Renderer renderer( rect, metrics, radial, QskGradient(), QskRgb::Black ); const auto lines = qskAllocateLines( geometry, renderer.borderCount() ); if ( lines ) diff --git a/src/nodes/QskFillNode.cpp b/src/nodes/QskFillNode.cpp index 99f20332..938dd7b0 100644 --- a/src/nodes/QskFillNode.cpp +++ b/src/nodes/QskFillNode.cpp @@ -136,10 +136,12 @@ void QskFillNode::setColoring( const QColor& color ) { setColoring( Monochrome ); + const auto colorRgb = color.toRgb(); + auto mat = static_cast< QSGFlatColorMaterial* >( material() ); - if ( mat->color() != color ) + if ( mat->color() != colorRgb ) { - mat->setColor( color ); + mat->setColor( colorRgb ); markDirty( QSGNode::DirtyMaterial ); } } @@ -148,16 +150,25 @@ void QskFillNode::setColoring( const QRectF& rect, const QskGradient& gradient ) { if ( gradient.isMonochrome() ) { - setColoring( gradient.startColor().toRgb() ); + setColoring( gradient.startColor() ); } else { - const auto effectiveGradient = gradient.effectiveGradient(); - setColoring( qskColoring( effectiveGradient.type() ) ); + if ( gradient.type() == QskGradient::Stops ) + { + qWarning() << "QskFillNode::setColoring:" + << "QskGradient::Stops is not supported, using the first color instead."; - auto mat = static_cast< QskGradientMaterial* >( material() ); - if ( mat->updateGradient( rect, effectiveGradient ) ) - markDirty( QSGNode::DirtyMaterial ); + setColoring( gradient.startColor() ); + } + else + { + setColoring( qskColoring( gradient.type() ) ); + + auto mat = static_cast< QskGradientMaterial* >( material() ); + if ( mat->updateGradient( rect, gradient ) ) + markDirty( QSGNode::DirtyMaterial ); + } } } From e9947c17a0cbee840f8226b1e4891001c58fbca8 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 24 Sep 2024 12:23:51 +0200 Subject: [PATCH 3/6] QskGradient::effectiveGradient moved to QskBoxRenderer::effectiveFradient as its implementation is not correct for arcs --- playground/gradients/GradientQuickShape.cpp | 3 ++- src/common/QskGradient.cpp | 15 --------------- src/common/QskGradient.h | 2 -- src/nodes/QskBoxRectangleNode.cpp | 6 +++--- src/nodes/QskBoxRenderer.cpp | 15 +++++++++++++++ src/nodes/QskBoxRenderer.h | 2 ++ 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/playground/gradients/GradientQuickShape.cpp b/playground/gradients/GradientQuickShape.cpp index cfe00b13..d71fd03c 100644 --- a/playground/gradients/GradientQuickShape.cpp +++ b/playground/gradients/GradientQuickShape.cpp @@ -7,6 +7,7 @@ #include #include +#include QSK_QT_PRIVATE_BEGIN @@ -54,7 +55,7 @@ namespace { QQuickShapeGradient* shapeGradient = nullptr; - auto effectiveGradient = gradient.effectiveGradient(); + auto effectiveGradient = QskBoxRenderer::effectiveGradient( gradient ); effectiveGradient.stretchTo( rect ); switch( static_cast< int >( effectiveGradient.type() ) ) diff --git a/src/common/QskGradient.cpp b/src/common/QskGradient.cpp index 3a66b5e8..7d552076 100644 --- a/src/common/QskGradient.cpp +++ b/src/common/QskGradient.cpp @@ -722,21 +722,6 @@ void QskGradient::resetDirection() m_values[0] = m_values[1] = m_values[2] = m_values[3] = m_values[4] = 0.0; } -QskGradient QskGradient::effectiveGradient() const -{ - if ( ( m_type == QskGradient::Stops ) || isMonochrome() ) - { - // the shader for linear gradients is the fastest - - QskGradient g = *this; - g.setDirection( QskGradient::Linear ); - - return g; - } - - return *this; -} - QGradient QskGradient::toQGradient() const { QGradient g; diff --git a/src/common/QskGradient.h b/src/common/QskGradient.h index 7e5fd665..f6757902 100644 --- a/src/common/QskGradient.h +++ b/src/common/QskGradient.h @@ -152,8 +152,6 @@ class QSK_EXPORT QskGradient QskGradient stretchedTo( const QSizeF& ) const; QskGradient stretchedTo( const QRectF& ) const; - QskGradient effectiveGradient() const; - static QVariant interpolate( const QskGradient&, const QskGradient&, qreal progress ); diff --git a/src/nodes/QskBoxRectangleNode.cpp b/src/nodes/QskBoxRectangleNode.cpp index 36f31d83..461e558b 100644 --- a/src/nodes/QskBoxRectangleNode.cpp +++ b/src/nodes/QskBoxRectangleNode.cpp @@ -103,7 +103,7 @@ void QskBoxRectangleNode::updateFilling( const QRectF& rect, return; } - const auto fillGradient = gradient.effectiveGradient(); + const auto fillGradient = QskBoxRenderer::effectiveGradient( gradient ); const auto shape = shapeMetrics.toAbsolute( rect.size() ); const bool coloredGeometry = hasHint( PreferColoredGeometry ) @@ -211,13 +211,13 @@ void QskBoxRectangleNode::updateBox( const QRectF& rect, if ( isDirty ) { /* - For monochrome border/fiiling with the same color we might be + For monochrome border/filling with the same color we might be able to do QskFillNode::Monochrome. However this is not implemeted in QskBoxRenderer yet. TODO ... */ setColoring( QskFillNode::Polychrome ); - auto fillGradient = gradient.effectiveGradient(); + auto fillGradient = QskBoxRenderer::effectiveGradient( gradient ); if ( !QskBoxRenderer::isGradientSupported( fillGradient ) ) { qWarning() << "QskBoxRenderer does not support radial/conic gradients"; diff --git a/src/nodes/QskBoxRenderer.cpp b/src/nodes/QskBoxRenderer.cpp index cb432d3c..eadd6693 100644 --- a/src/nodes/QskBoxRenderer.cpp +++ b/src/nodes/QskBoxRenderer.cpp @@ -231,3 +231,18 @@ void QskBoxRenderer::setColoredBorderAndFillLines( const QRectF& rect, } } } + +QskGradient QskBoxRenderer::effectiveGradient( const QskGradient& gradient ) +{ + if ( ( gradient.type() == QskGradient::Stops ) || gradient.isMonochrome() ) + { + // the shader for linear gradients is the fastest + + auto g = gradient; + g.setDirection( QskGradient::Linear ); + + return g; + } + + return gradient; +} diff --git a/src/nodes/QskBoxRenderer.h b/src/nodes/QskBoxRenderer.h index 2f8c89fc..9b30eb88 100644 --- a/src/nodes/QskBoxRenderer.h +++ b/src/nodes/QskBoxRenderer.h @@ -54,6 +54,8 @@ namespace QskBoxRenderer QSK_EXPORT void setColoredBorderAndFillLines( const QRectF&, const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, const QskBoxBorderColors&, const QskGradient&, QSGGeometry& ); + + QSK_EXPORT QskGradient effectiveGradient( const QskGradient& ); } #endif From ae9bc90d3862b9f34a59c927c511e94546d377fd Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 25 Sep 2024 07:51:02 +0200 Subject: [PATCH 4/6] eliminating the index buffer --- src/nodes/QskShapeNode.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/nodes/QskShapeNode.cpp b/src/nodes/QskShapeNode.cpp index fc6b5f9a..af973f1a 100644 --- a/src/nodes/QskShapeNode.cpp +++ b/src/nodes/QskShapeNode.cpp @@ -13,12 +13,14 @@ QSK_QT_PRIVATE_BEGIN #include QSK_QT_PRIVATE_END +#if 0 + +// keeping the index list static void qskUpdateGeometry( const QPainterPath& path, const QTransform& transform, QSGGeometry& geometry ) { const auto ts = qTriangulate( path, transform, 1, false ); -#if 1 geometry.allocate( ts.vertices.size(), ts.indices.size() ); auto vertexData = reinterpret_cast< float* >( geometry.vertexData() ); @@ -29,11 +31,22 @@ static void qskUpdateGeometry( const QPainterPath& path, memcpy( geometry.indexData(), ts.indices.data(), ts.indices.size() * sizeof( quint16 ) ); -#else +} + +#endif + +static void qskUpdateGeometry( const QPainterPath& path, + const QTransform& transform, QSGGeometry& geometry ) +{ + const auto ts = qTriangulate( path, transform, 1, false ); + /* + The triangulation of a random path does not lead to index lists + that are substantially reducing the number of vertices. + As we have to iterate over the vertex buffer to copy qreal to float - anyway we could reorder according to the index buffer and drop - the index buffer then ??? + anyway we reorder according to the index buffer and drop + the index buffer. QTriangleSet: @@ -41,6 +54,7 @@ static void qskUpdateGeometry( const QPainterPath& path, QVector vertices; // [x[0], y[0], x[1], y[1], x[2], ...] QVector indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...] */ + const auto points = ts.vertices.constData(); const auto indices = reinterpret_cast< const quint16* >( ts.indices.data() ); @@ -52,7 +66,6 @@ static void qskUpdateGeometry( const QPainterPath& path, const int j = 2 * indices[i]; vertexData[i].set( points[j], points[j + 1] ); } -#endif } class QskShapeNodePrivate final : public QskFillNodePrivate From 6e15e74061689b8d1ad7487b6ca8690bf313dbf9 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 25 Sep 2024 13:52:12 +0200 Subject: [PATCH 5/6] missing return added --- src/dialogs/QskSelectionSubWindow.cpp | 2 +- src/dialogs/QskSelectionWindow.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dialogs/QskSelectionSubWindow.cpp b/src/dialogs/QskSelectionSubWindow.cpp index 44e44b72..b8c99277 100644 --- a/src/dialogs/QskSelectionSubWindow.cpp +++ b/src/dialogs/QskSelectionSubWindow.cpp @@ -90,7 +90,7 @@ int QskSelectionSubWindow::selectedRow() const QString QskSelectionSubWindow::selectedEntry() const { if ( auto listBox = qskListBox( this ) ) - listBox->selectedEntry(); + return listBox->selectedEntry(); return QString(); } diff --git a/src/dialogs/QskSelectionWindow.cpp b/src/dialogs/QskSelectionWindow.cpp index 1d0baa1d..e54b3369 100644 --- a/src/dialogs/QskSelectionWindow.cpp +++ b/src/dialogs/QskSelectionWindow.cpp @@ -93,7 +93,7 @@ int QskSelectionWindow::selectedRow() const QString QskSelectionWindow::selectedEntry() const { if ( auto listBox = qskListBox( this ) ) - listBox->selectedEntry(); + return listBox->selectedEntry(); return QString(); } From 283afee43aac3ce22001c5243891b5003876aa32 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 25 Sep 2024 15:51:01 +0200 Subject: [PATCH 6/6] using QSGVertexColorMaterial for monochrome gradients, when requested by QskFillNode::PreferColoredGeometry ( = default ). might be useful for batching --- src/nodes/QskShapeNode.cpp | 50 ++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/src/nodes/QskShapeNode.cpp b/src/nodes/QskShapeNode.cpp index af973f1a..b2d4b78d 100644 --- a/src/nodes/QskShapeNode.cpp +++ b/src/nodes/QskShapeNode.cpp @@ -6,6 +6,7 @@ #include "QskShapeNode.h" #include "QskGradient.h" #include "QskGradientDirection.h" +#include "QskVertex.h" #include "QskFillNodePrivate.h" QSK_QT_PRIVATE_BEGIN @@ -26,7 +27,7 @@ static void qskUpdateGeometry( const QPainterPath& path, auto vertexData = reinterpret_cast< float* >( geometry.vertexData() ); const auto points = ts.vertices.constData(); - for ( int i = 0; i < ts.vertices.count(); i++ ) + for ( int i = 0; i < ts.vertices.size(); i++ ) vertexData[i] = points[i]; memcpy( geometry.indexData(), ts.indices.data(), @@ -36,17 +37,17 @@ static void qskUpdateGeometry( const QPainterPath& path, #endif static void qskUpdateGeometry( const QPainterPath& path, - const QTransform& transform, QSGGeometry& geometry ) + const QTransform& transform, const QColor& color, QSGGeometry& geometry ) { const auto ts = qTriangulate( path, transform, 1, false ); /* - The triangulation of a random path does not lead to index lists - that are substantially reducing the number of vertices. + The triangulation of a random path usually does not lead to index lists + that allow substantially reducing the number of vertices. As we have to iterate over the vertex buffer to copy qreal to float anyway we reorder according to the index buffer and drop - the index buffer. + the index buffer. QTriangleSet: @@ -60,11 +61,25 @@ static void qskUpdateGeometry( const QPainterPath& path, geometry.allocate( ts.indices.size() ); - auto vertexData = geometry.vertexDataAsPoint2D(); - for ( int i = 0; i < ts.indices.size(); i++ ) + if ( color.isValid() ) { - const int j = 2 * indices[i]; - vertexData[i].set( points[j], points[j + 1] ); + const QskVertex::Color c = color; + + auto vertexData = geometry.vertexDataAsColoredPoint2D(); + for ( int i = 0; i < ts.indices.size(); i++ ) + { + const int j = 2 * indices[i]; + vertexData[i].set( points[j], points[j + 1], c.r, c.g, c.b, c.a ); + } + } + else + { + auto vertexData = geometry.vertexDataAsPoint2D(); + for ( int i = 0; i < ts.indices.size(); i++ ) + { + const int j = 2 * indices[i]; + vertexData[i].set( points[j], points[j + 1] ); + } } } @@ -82,7 +97,6 @@ class QskShapeNodePrivate final : public QskFillNodePrivate QskShapeNode::QskShapeNode() : QskFillNode( *new QskShapeNodePrivate ) { - setColoring( Monochrome ); geometry()->setDrawingMode( QSGGeometry::DrawTriangles ); } @@ -104,14 +118,24 @@ void QskShapeNode::updateNode( const QPainterPath& path, return; } - setColoring( rect, gradient ); + QColor c; - if ( ( transform != d->transform ) || ( path != d->path ) ) + if ( gradient.isMonochrome() && hasHint( PreferColoredGeometry ) ) + c = gradient.startColor(); + + const bool isDirty = ( isGeometryColored() != c.isValid() ); + + if ( c.isValid() ) + setColoring( QskFillNode::Polychrome ); + else + setColoring( rect, gradient ); + + if ( isDirty || ( transform != d->transform ) || ( path != d->path ) ) { d->path = path; d->transform = transform; - qskUpdateGeometry( path, transform, *geometry() ); + qskUpdateGeometry( path, transform, c, *geometry() ); geometry()->markVertexDataDirty(); markDirty( QSGNode::DirtyGeometry );