smarter matrial updates

This commit is contained in:
Uwe Rathmann 2022-09-29 12:40:22 +02:00
parent b138d04053
commit 634ca3bed3
3 changed files with 259 additions and 76 deletions

View File

@ -229,9 +229,8 @@ namespace
class GradientMaterial : public QskGradientMaterial
{
public:
GradientMaterial( QGradient::Type type,
const QGradientStops& stops, QGradient::Spread spread )
: QskGradientMaterial( type, stops, spread )
GradientMaterial( QGradient::Type type )
: QskGradientMaterial( type )
{
setFlag( Blending | RequiresFullMatrix );
@ -355,16 +354,39 @@ namespace
class LinearMaterial final : public GradientMaterial
{
public:
LinearMaterial(
const QGradientStops& stops, QGradient::Spread spread,
const QPointF& start, const QPointF& stop )
: GradientMaterial( QGradient::LinearGradient, stops, spread )
, m_start( start )
, m_stop( stop )
LinearMaterial()
: GradientMaterial( QGradient::LinearGradient )
{
}
QSGMaterialShader* createShader() const override;
bool setGradient( const QLinearGradient* gradient )
{
bool changed = false;
if ( gradient->stops() != stops() )
{
setStops( gradient->stops() );
changed = true;
}
if ( gradient->spread() != spread() )
{
setSpread( gradient->spread() );
changed = true;
}
const QVector2D start( gradient->start() );
const QVector2D stop( gradient->finalStop() );
if ( m_start != start || m_stop != stop )
{
m_start = start;
m_stop = stop;
changed = true;
}
return changed;
}
QSGMaterialType* type() const override
{
@ -382,8 +404,10 @@ namespace
return GradientMaterial::compare( other );
}
const QVector2D m_start;
const QVector2D m_stop;
QSGMaterialShader* createShader() const override;
QVector2D m_start;
QVector2D m_stop;
};
#ifdef SHADER_GL
@ -485,26 +509,58 @@ namespace
class RadialMaterial final : public GradientMaterial
{
public:
RadialMaterial(
const QGradientStops& stops, QGradient::Spread spread,
const QPointF& center, qreal centerRadius,
const QPointF& focalPoint, qreal focalRadius )
: GradientMaterial( QGradient::RadialGradient, stops, spread )
, m_center( center )
, m_focalPoint( focalPoint )
, m_centerRadius( centerRadius )
, m_focalRadius( focalRadius )
RadialMaterial()
: GradientMaterial( QGradient::RadialGradient )
{
}
QSGMaterialShader* createShader() const override;
QSGMaterialType* type() const override
{
static QSGMaterialType type;
return &type;
}
bool setGradient( const QRadialGradient* gradient )
{
bool changed = false;
if ( gradient->stops() != stops() )
{
setStops( gradient->stops() );
changed = true;
}
if ( gradient->spread() != spread() )
{
setSpread( gradient->spread() );
changed = true;
}
const QVector2D center( gradient->center() );
const float centerRadius = gradient->centerRadius();
if ( ( center != m_center ) || ( m_centerRadius != centerRadius ) )
{
m_center = center;
m_centerRadius = centerRadius;
changed = true;
}
const QVector2D focalPoint( gradient->focalPoint() );
const float focalRadius = gradient->focalRadius();
if ( ( focalPoint != m_focalPoint ) || ( focalRadius != m_focalRadius ) )
{
m_focalPoint = focalPoint;
m_focalRadius = focalRadius;
changed = true;
}
return changed;
}
int compare( const QSGMaterial* other ) const override
{
const auto mat = static_cast< const RadialMaterial* >( other );
@ -522,10 +578,12 @@ namespace
}
}
const QVector2D m_center;
const QVector2D m_focalPoint;
const float m_centerRadius;
const float m_focalRadius;
QSGMaterialShader* createShader() const override;
QVector2D m_center;
QVector2D m_focalPoint;
float m_centerRadius = 0.0;
float m_focalRadius = 0.0;
};
#ifdef SHADER_GL
@ -650,22 +708,41 @@ namespace
class ConicalMaterial final : public GradientMaterial
{
public:
ConicalMaterial( const QGradientStops& stops,
const QPointF& center, qreal angle )
: GradientMaterial( QGradient::ConicalGradient, stops, QGradient::PadSpread )
, m_center( center )
, m_radians( -qDegreesToRadians( angle ) )
ConicalMaterial()
: GradientMaterial( QGradient::ConicalGradient )
{
}
QSGMaterialShader* createShader() const override;
QSGMaterialType* type() const override
{
static QSGMaterialType type;
return &type;
}
bool setGradient( const QConicalGradient* gradient )
{
bool changed = false;
if ( gradient->stops() != stops() )
{
setStops( gradient->stops() );
changed = true;
}
const QVector2D center( gradient->center() );
const float radians = -qDegreesToRadians( gradient->angle() );
if ( center != m_center || radians != m_radians )
{
m_center = center;
m_radians = radians;
changed = true;
}
return changed;
}
int compare( const QSGMaterial* other ) const override
{
const auto mat = static_cast< const ConicalMaterial* >( other );
@ -676,8 +753,10 @@ namespace
return GradientMaterial::compare( other );
}
const QVector2D m_center;
const float m_radians;
QSGMaterialShader* createShader() const override;
QVector2D m_center;
float m_radians = 0.0;
};
#ifdef SHADER_GL
@ -774,39 +853,65 @@ namespace
}
}
QskGradientMaterial* QskGradientMaterial::create( const QGradient* gradient )
QskGradientMaterial::QskGradientMaterial( QGradient::Type type )
: m_gradientType( type )
{
}
template< typename Material >
inline Material* qskEnsureMaterial( QskGradientMaterial* material )
{
if ( material == nullptr )
material = new Material();
return static_cast< Material* >( material );
}
bool QskGradientMaterial::updateGradient( const QGradient* gradient )
{
Q_ASSERT( gradient && gradient->type() == m_gradientType );
if ( gradient == nullptr || gradient->type() != m_gradientType )
return false;
switch ( static_cast< int >( gradient->type() ) )
{
case QGradient::LinearGradient:
{
auto linearGradient = static_cast< const QLinearGradient* >( gradient );
return new LinearMaterial(
linearGradient->stops(), linearGradient->spread(),
linearGradient->start(), linearGradient->finalStop() );
auto material = static_cast< LinearMaterial* >( this );
return material->setGradient( static_cast< const QLinearGradient* >( gradient ) );
}
case QGradient::RadialGradient:
{
auto radialGradient = static_cast< const QRadialGradient* >( gradient );
return new RadialMaterial(
radialGradient->stops(), radialGradient->spread(),
radialGradient->center(), radialGradient->centerRadius(),
radialGradient->focalPoint(), radialGradient->focalRadius() );
auto material = static_cast< RadialMaterial* >( this );
return material->setGradient( static_cast< const QRadialGradient* >( gradient ) );
}
case QGradient::ConicalGradient:
{
auto conicalGradient = static_cast< const QConicalGradient* >( gradient );
return new ConicalMaterial( conicalGradient->stops(),
conicalGradient->center(), conicalGradient->angle() );
auto material = static_cast< ConicalMaterial* >( this );
return material->setGradient( static_cast< const QConicalGradient* >( gradient ) );
}
}
return nullptr;
return false;
}
QskGradientMaterial* QskGradientMaterial::createMaterial( QGradient::Type gradientType )
{
switch ( gradientType )
{
case QGradient::LinearGradient:
return new LinearMaterial();
case QGradient::RadialGradient:
return new RadialMaterial();
case QGradient::ConicalGradient:
return new ConicalMaterial();
default:
return nullptr;
}
}

View File

@ -13,36 +13,42 @@
class QSK_EXPORT QskGradientMaterial : public QSGMaterial
{
public:
static QskGradientMaterial* create( const QGradient* );
static QskGradientMaterial* createMaterial( QGradient::Type );
bool updateGradient( const QGradient* );
QGradient::Type gradientType() const;
const QGradientStops& stops() const;
QGradient::Spread spread() const;
protected:
QskGradientMaterial( QGradient::Type,
const QGradientStops&, QGradient::Spread );
QskGradientMaterial( QGradient::Type );
void setStops( const QGradientStops& );
void setSpread( QGradient::Spread );
private:
const QGradient::Type m_gradientType;
const QGradientStops m_stops;
const QGradient::Spread m_spread;
};
inline QskGradientMaterial::QskGradientMaterial( QGradient::Type type,
const QGradientStops& stops, QGradient::Spread spread )
: m_gradientType( type )
, m_stops( stops )
, m_spread( spread )
{
}
QGradientStops m_stops;
QGradient::Spread m_spread = QGradient::PadSpread;
};
inline QGradient::Type QskGradientMaterial::gradientType() const
{
return m_gradientType;
}
inline void QskGradientMaterial::setStops( const QGradientStops& stops )
{
m_stops = stops;
}
inline void QskGradientMaterial::setSpread( QGradient::Spread spread )
{
m_spread = spread;
}
inline const QGradientStops& QskGradientMaterial::stops() const
{
return m_stops;

View File

@ -56,6 +56,46 @@ static void qskUpdateGeometry( const QPainterPath& path, QSGGeometry& geometry )
#endif
}
static inline void qskResetGeometry( QskShapeNode* node )
{
auto g = node->geometry();
if ( g->vertexCount() > 0 )
{
g->allocate( 0 );
node->markDirty( QSGNode::DirtyGeometry );
}
}
static inline bool qskIsGradientVisible( const QGradient* gradient )
{
if ( gradient && gradient->type() != QGradient::NoGradient )
{
for ( const auto stop : gradient->stops() )
{
if ( stop.second.alpha() > 0 )
return true;
}
}
return false;
}
static inline bool qskIsGradientMonochrome( const QGradient* gradient )
{
if ( gradient && gradient->type() != QGradient::NoGradient )
{
const auto stops = gradient->stops();
for ( int i = 1; i < stops.count(); i++ )
{
if ( stops[i].second != stops[i - 1].second )
return false;
}
}
return true;
}
class QskShapeNodePrivate final : public QSGGeometryNodePrivate
{
public:
@ -66,7 +106,7 @@ class QskShapeNodePrivate final : public QSGGeometryNodePrivate
}
QSGGeometry geometry;
QSGMaterial* material = nullptr;
QGradient::Type gradientType = QGradient::NoGradient;
};
QskShapeNode::QskShapeNode()
@ -80,33 +120,65 @@ QskShapeNode::QskShapeNode()
void QskShapeNode::updateNode( const QPainterPath& path, const QColor& color )
{
Q_D( QskShapeNode );
if ( path.isEmpty() || !color.isValid() || color.alpha() == 0 )
{
qskResetGeometry( this );
return;
}
if ( true ) // For the moment we always update the geometry. TODO ...
{
qskUpdateGeometry( path, *geometry() );
qskUpdateGeometry( path, d->geometry );
markDirty( QSGNode::DirtyGeometry );
}
if ( true ) // For the moment we always update the material
if ( material() == nullptr || d->gradientType != QGradient::NoGradient )
{
auto material = new QSGFlatColorMaterial();
material->setColor( color );
setMaterial( new QSGFlatColorMaterial() );
d->gradientType = QGradient::NoGradient;
}
setMaterial( material );
const auto c = color.toRgb();
auto colorMaterial = static_cast< QSGFlatColorMaterial* >( material() );
if ( colorMaterial->color() != c )
{
colorMaterial->setColor( c );
markDirty( QSGNode::DirtyMaterial );
}
}
void QskShapeNode::updateNode( const QPainterPath& path, const QGradient* gradient )
{
if ( path.isEmpty() || !qskIsGradientVisible( gradient ) )
{
qskResetGeometry( this );
return;
}
if ( qskIsGradientMonochrome( gradient ) )
{
updateNode( path, gradient->stops().first().first );
return;
}
Q_D( QskShapeNode );
if ( true ) // For the moment we always update the geometry. TODO ...
{
qskUpdateGeometry( path, *geometry() );
qskUpdateGeometry( path, d->geometry );
markDirty( QSGNode::DirtyGeometry );
}
if ( true ) // For the moment we always update the material
if ( ( material() == nullptr ) || gradient->type() != d->gradientType )
{
setMaterial( QskGradientMaterial::create( gradient ) );
markDirty( QSGNode::DirtyMaterial );
setMaterial( QskGradientMaterial::createMaterial( gradient->type() ) );
d->gradientType = gradient->type();
}
auto gradientMaterial = static_cast< QskGradientMaterial* >( material() );
if ( gradientMaterial->updateGradient( gradient ) )
markDirty( QSGNode::DirtyMaterial );
}