diff --git a/playground/gradients/GradientQuickShape.cpp b/playground/gradients/GradientQuickShape.cpp index 9ace9733..d71fd03c 100644 --- a/playground/gradients/GradientQuickShape.cpp +++ b/playground/gradients/GradientQuickShape.cpp @@ -7,6 +7,7 @@ #include #include +#include QSK_QT_PRIVATE_BEGIN @@ -54,10 +55,10 @@ namespace { QQuickShapeGradient* shapeGradient = nullptr; - auto effectiveGradient = gradient.effectiveGradient(); + auto effectiveGradient = QskBoxRenderer::effectiveGradient( gradient ); effectiveGradient.stretchTo( rect ); - switch( static_cast< int >( gradient.type() ) ) + switch( static_cast< int >( effectiveGradient.type() ) ) { case QskGradient::Linear: { 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/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(); } 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/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 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 ); + } } } diff --git a/src/nodes/QskShapeNode.cpp b/src/nodes/QskShapeNode.cpp index fc6b5f9a..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 @@ -13,27 +14,40 @@ 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() ); 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(), ts.indices.size() * sizeof( quint16 ) ); -#else +} + +#endif + +static void qskUpdateGeometry( const QPainterPath& path, + const QTransform& transform, const QColor& color, QSGGeometry& geometry ) +{ + const auto ts = qTriangulate( path, transform, 1, false ); + /* + 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 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,18 +55,32 @@ 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() ); 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] ); + } } -#endif } class QskShapeNodePrivate final : public QskFillNodePrivate @@ -69,7 +97,6 @@ class QskShapeNodePrivate final : public QskFillNodePrivate QskShapeNode::QskShapeNode() : QskFillNode( *new QskShapeNodePrivate ) { - setColoring( Monochrome ); geometry()->setDrawingMode( QSGGeometry::DrawTriangles ); } @@ -91,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 );