update issues with gradients fixed

This commit is contained in:
Uwe Rathmann 2022-12-10 16:08:32 +01:00
parent a48943e68f
commit 8318ff757b
5 changed files with 77 additions and 48 deletions

View File

@ -94,8 +94,8 @@ class GradientBox: public QWidget
m_qskBox = new BoxQsk(); m_qskBox = new BoxQsk();
auto layout = new QHBoxLayout( this ); auto layout = new QHBoxLayout( this );
layout->addWidget( m_qskBox );
layout->addWidget( m_qtBox ); layout->addWidget( m_qtBox );
layout->addWidget( m_qskBox );
showGradient( { Qt::green, Qt::red, Qt::yellow, Qt::cyan, Qt::darkCyan } ); 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] }; 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 ); gradient.setStops( stops );
showGradient( gradient ); showGradient( gradient );

View File

@ -50,9 +50,18 @@ class QskBoxFillNodePrivate final : public QSGGeometryNodePrivate
{ {
} }
QskHashValue metricsHash = 0; inline void resetValues()
{
rect = QRectF();
gradientHash = 0;
metricsHash = 0;
}
QRectF rect; QRectF rect;
QskHashValue gradientHash = 0;
QskHashValue metricsHash = 0;
QSGGeometry geometry; QSGGeometry geometry;
int gradientType = -1; int gradientType = -1;
}; };
@ -75,20 +84,23 @@ void QskBoxFillNode::updateNode(
if ( rect.isEmpty() || !gradient.isVisible() ) if ( rect.isEmpty() || !gradient.isVisible() )
{ {
d->rect = QRectF(); d->resetValues();
d->metricsHash = 0;
QskSGNode::resetGeometry( this ); QskSGNode::resetGeometry( this );
return; return;
} }
const auto metricsHash = qskMetricsHash( shapeMetrics, borderMetrics ); 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->metricsHash = metricsHash;
d->gradientHash = gradientHash;
d->rect = rect; d->rect = rect;
if ( dirtyGeometry ) if ( dirtyMetrics )
{ {
QskBoxRenderer::renderFill( rect, shapeMetrics, borderMetrics, d->geometry ); QskBoxRenderer::renderFill( rect, shapeMetrics, borderMetrics, d->geometry );
markDirty( QSGNode::DirtyGeometry ); markDirty( QSGNode::DirtyGeometry );
@ -96,34 +108,42 @@ void QskBoxFillNode::updateNode(
if ( gradient.isMonochrome() ) if ( gradient.isMonochrome() )
{ {
if ( material() == nullptr || d->gradientType >= 0 ) if ( dirtyColors )
{ {
setMaterial( new QSGFlatColorMaterial() ); if ( material() == nullptr || d->gradientType >= 0 )
d->gradientType = -1; {
} setMaterial( new QSGFlatColorMaterial() );
d->gradientType = -1;
}
const auto color = gradient.startColor().toRgb(); const auto color = gradient.startColor().toRgb();
auto mat = static_cast< QSGFlatColorMaterial* >( material() ); auto mat = static_cast< QSGFlatColorMaterial* >( material() );
if ( mat->color() != color ) if ( mat->color() != color )
{ {
mat->setColor( color ); mat->setColor( color );
markDirty( QSGNode::DirtyMaterial ); markDirty( QSGNode::DirtyMaterial );
}
} }
} }
else else
{ {
const auto effectiveGradient = qskEffectiveGradient( gradient ); // dirtyMetrics: the shader also depends on the target rectangle !
const auto gradientType = effectiveGradient.type();
if ( ( material() == nullptr ) || ( gradientType != d->gradientType ) ) if ( dirtyColors || dirtyMetrics )
{ {
setMaterial( QskGradientMaterial::createMaterial( gradientType ) ); const auto effectiveGradient = qskEffectiveGradient( gradient );
d->gradientType = gradientType; const auto gradientType = effectiveGradient.type();
}
auto mat = static_cast< QskGradientMaterial* >( material() ); if ( ( material() == nullptr ) || ( gradientType != d->gradientType ) )
if ( mat->updateGradient( rect, effectiveGradient ) ) {
markDirty( QSGNode::DirtyMaterial ); setMaterial( QskGradientMaterial::createMaterial( gradientType ) );
d->gradientType = gradientType;
}
auto mat = static_cast< QskGradientMaterial* >( material() );
if ( mat->updateGradient( rect, effectiveGradient ) )
markDirty( QSGNode::DirtyMaterial );
}
} }
} }

View File

@ -43,32 +43,33 @@ void QskBoxRenderer::renderBox( const QRectF& rect,
bool QskBoxRenderer::isGradientSupported( bool QskBoxRenderer::isGradientSupported(
const QskBoxShapeMetrics&, const QskGradient& gradient ) const QskBoxShapeMetrics&, const QskGradient& gradient )
{ {
if ( !gradient.isVisible() || gradient.isMonochrome() ) if ( !gradient.isVisible() || gradient.isMonochrome()
return true; || ( gradient.type() == QskGradient::Stops ) )
switch( gradient.type() )
{ {
case QskGradient::Linear: return true;
{ }
auto dir = gradient.linearDirection();
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 true;
return ( dir.x1() == 0.0 ) && ( dir.y1() == 0.0 )
&& ( dir.x2() == 1.0 ) && ( dir.y2() == 1.0 );
} }
}
else
{
if ( dir.x1() == 0.0 && dir.x2() == 1.0 )
return true;
return true; if ( dir.y1() == 0.0 && dir.y2() == 1.0 )
} return true;
case QskGradient::Radial:
case QskGradient::Conic:
{
return false;
}
default:
{
return true;
} }
} }
return false;
} }

View File

@ -180,6 +180,12 @@ namespace
changed = true; 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() ) if ( gradient.spread() != spread() )
{ {
setSpread( gradient.spread() ); setSpread( gradient.spread() );

View File

@ -188,7 +188,8 @@ void QskRectangleNode::updateNode(
markDirty( QSGNode::DirtyGeometry ); markDirty( QSGNode::DirtyGeometry );
} }
if ( dirtyColors ) // dirtyMetrics: the shader also depends on the target rectangle !
if ( dirtyColors || dirtyMetrics )
{ {
const auto gradientType = effectiveGradient.type(); const auto gradientType = effectiveGradient.type();