diff --git a/playground/gradients/main.cpp b/playground/gradients/main.cpp index e3aa704c..02c9dc49 100644 --- a/playground/gradients/main.cpp +++ b/playground/gradients/main.cpp @@ -94,8 +94,8 @@ class GradientBox: public QWidget m_qskBox = new BoxQsk(); auto layout = new QHBoxLayout( this ); - layout->addWidget( m_qskBox ); layout->addWidget( m_qtBox ); + layout->addWidget( m_qskBox ); showGradient( { Qt::green, Qt::red, Qt::yellow, Qt::cyan, Qt::darkCyan } ); } @@ -116,7 +116,8 @@ class GradientBox: public QWidget stops += { ( i + 1 ) * step, colors[i] }; } - QLinearGradient gradient( 0.0, 0.0, 0.0, 1.0 ); + QLinearGradient gradient( 0.0, 0.0, 0.5, 0.5 ); + gradient.setSpread( QGradient::ReflectSpread ); gradient.setStops( stops ); showGradient( gradient ); diff --git a/src/nodes/QskBoxFillNode.cpp b/src/nodes/QskBoxFillNode.cpp index ac1cca65..3d99ca87 100644 --- a/src/nodes/QskBoxFillNode.cpp +++ b/src/nodes/QskBoxFillNode.cpp @@ -50,9 +50,18 @@ class QskBoxFillNodePrivate final : public QSGGeometryNodePrivate { } - QskHashValue metricsHash = 0; + inline void resetValues() + { + rect = QRectF(); + gradientHash = 0; + metricsHash = 0; + } + QRectF rect; + QskHashValue gradientHash = 0; + QskHashValue metricsHash = 0; + QSGGeometry geometry; int gradientType = -1; }; @@ -75,20 +84,23 @@ void QskBoxFillNode::updateNode( if ( rect.isEmpty() || !gradient.isVisible() ) { - d->rect = QRectF(); - d->metricsHash = 0; + d->resetValues(); QskSGNode::resetGeometry( this ); return; } const auto metricsHash = qskMetricsHash( shapeMetrics, borderMetrics ); - const bool dirtyGeometry = ( metricsHash != d->metricsHash ) || ( rect != d->rect ); + const auto gradientHash = gradient.hash( 22879 ); + + const bool dirtyColors = gradientHash != d->gradientHash; + const bool dirtyMetrics = ( metricsHash != d->metricsHash ) || ( rect != d->rect ); d->metricsHash = metricsHash; + d->gradientHash = gradientHash; d->rect = rect; - if ( dirtyGeometry ) + if ( dirtyMetrics ) { QskBoxRenderer::renderFill( rect, shapeMetrics, borderMetrics, d->geometry ); markDirty( QSGNode::DirtyGeometry ); @@ -96,34 +108,42 @@ void QskBoxFillNode::updateNode( if ( gradient.isMonochrome() ) { - if ( material() == nullptr || d->gradientType >= 0 ) + if ( dirtyColors ) { - setMaterial( new QSGFlatColorMaterial() ); - d->gradientType = -1; - } + if ( material() == nullptr || d->gradientType >= 0 ) + { + setMaterial( new QSGFlatColorMaterial() ); + d->gradientType = -1; + } - const auto color = gradient.startColor().toRgb(); + const auto color = gradient.startColor().toRgb(); - auto mat = static_cast< QSGFlatColorMaterial* >( material() ); - if ( mat->color() != color ) - { - mat->setColor( color ); - markDirty( QSGNode::DirtyMaterial ); + auto mat = static_cast< QSGFlatColorMaterial* >( material() ); + if ( mat->color() != color ) + { + mat->setColor( color ); + markDirty( QSGNode::DirtyMaterial ); + } } } else { - const auto effectiveGradient = qskEffectiveGradient( gradient ); - const auto gradientType = effectiveGradient.type(); + // dirtyMetrics: the shader also depends on the target rectangle ! - if ( ( material() == nullptr ) || ( gradientType != d->gradientType ) ) + if ( dirtyColors || dirtyMetrics ) { - setMaterial( QskGradientMaterial::createMaterial( gradientType ) ); - d->gradientType = gradientType; - } + const auto effectiveGradient = qskEffectiveGradient( gradient ); + const auto gradientType = effectiveGradient.type(); - auto mat = static_cast< QskGradientMaterial* >( material() ); - if ( mat->updateGradient( rect, effectiveGradient ) ) - markDirty( QSGNode::DirtyMaterial ); + if ( ( material() == nullptr ) || ( gradientType != d->gradientType ) ) + { + setMaterial( QskGradientMaterial::createMaterial( gradientType ) ); + d->gradientType = gradientType; + } + + auto mat = static_cast< QskGradientMaterial* >( material() ); + if ( mat->updateGradient( rect, effectiveGradient ) ) + markDirty( QSGNode::DirtyMaterial ); + } } } diff --git a/src/nodes/QskBoxRenderer.cpp b/src/nodes/QskBoxRenderer.cpp index d2116f57..fdbafee3 100644 --- a/src/nodes/QskBoxRenderer.cpp +++ b/src/nodes/QskBoxRenderer.cpp @@ -43,32 +43,33 @@ void QskBoxRenderer::renderBox( const QRectF& rect, bool QskBoxRenderer::isGradientSupported( const QskBoxShapeMetrics&, const QskGradient& gradient ) { - if ( !gradient.isVisible() || gradient.isMonochrome() ) - return true; - - switch( gradient.type() ) + if ( !gradient.isVisible() || gradient.isMonochrome() + || ( gradient.type() == QskGradient::Stops ) ) { - case QskGradient::Linear: - { - auto dir = gradient.linearDirection(); + return true; + } - if ( dir.isTilted() ) + if ( gradient.type() == QskGradient::Linear ) + { + const auto dir = gradient.linearDirection(); + + if ( dir.isTilted() ) + { + if ( dir.x1() == 0.0 && dir.y1() == 0.0 + && dir.x2() == 1.0 && dir.y2() == 1.0 ) { - // only diagonal from topLeft to bottomRight - return ( dir.x1() == 0.0 ) && ( dir.y1() == 0.0 ) - && ( dir.x2() == 1.0 ) && ( dir.y2() == 1.0 ); + return true; } + } + else + { + if ( dir.x1() == 0.0 && dir.x2() == 1.0 ) + return true; - return true; - } - case QskGradient::Radial: - case QskGradient::Conic: - { - return false; - } - default: - { - return true; + if ( dir.y1() == 0.0 && dir.y2() == 1.0 ) + return true; } } + + return false; } diff --git a/src/nodes/QskGradientMaterial.cpp b/src/nodes/QskGradientMaterial.cpp index f80bf783..b03b4a9b 100644 --- a/src/nodes/QskGradientMaterial.cpp +++ b/src/nodes/QskGradientMaterial.cpp @@ -180,6 +180,12 @@ namespace changed = true; } + /* + When having a gradient, that does not need spreading + we could set QskGradient::PadSpread to potentally reduce + the number of color ramps. TODO ... + */ + if ( gradient.spread() != spread() ) { setSpread( gradient.spread() ); diff --git a/src/nodes/QskRectangleNode.cpp b/src/nodes/QskRectangleNode.cpp index 4c029cce..ab2ecb38 100644 --- a/src/nodes/QskRectangleNode.cpp +++ b/src/nodes/QskRectangleNode.cpp @@ -188,7 +188,8 @@ void QskRectangleNode::updateNode( markDirty( QSGNode::DirtyGeometry ); } - if ( dirtyColors ) + // dirtyMetrics: the shader also depends on the target rectangle ! + if ( dirtyColors || dirtyMetrics ) { const auto gradientType = effectiveGradient.type();