From 6d726eee0ab60c73ec9f0612613946800aefbcfe Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 5 Dec 2022 17:10:13 +0100 Subject: [PATCH] QskGradientNode introduced for rectangles filled with any type of gradient being supported by QskGradient. It is lighter than QskBoxNode, that is a compositition of border/gradient/shadow. Used for the background node now - what means, that background can have radial/conic gradients now as well. --- src/controls/QskSkinlet.cpp | 5 +- src/nodes/QskGradientNode.cpp | 166 ++++++++++++++++++++++++++++++++++ src/nodes/QskGradientNode.h | 27 ++++++ src/src.pro | 2 + 4 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 src/nodes/QskGradientNode.cpp create mode 100644 src/nodes/QskGradientNode.h diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index faa8740b..e72d0500 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -19,6 +19,7 @@ #include "QskControl.h" #include "QskFunctions.h" #include "QskGradient.h" +#include "QskGradientNode.h" #include "QskGraphicNode.h" #include "QskGraphic.h" #include "QskSGNode.h" @@ -350,9 +351,9 @@ QSGNode* QskSkinlet::updateBackgroundNode( if ( !gradient.isValid() ) return nullptr; - auto rectNode = static_cast< QskBoxRectangleNode* >( node ); + auto rectNode = static_cast< QskGradientNode* >( node ); if ( rectNode == nullptr ) - rectNode = new QskBoxRectangleNode(); + rectNode = new QskGradientNode(); rectNode->updateNode( rect, gradient ); return rectNode; diff --git a/src/nodes/QskGradientNode.cpp b/src/nodes/QskGradientNode.cpp new file mode 100644 index 00000000..02a8d1b5 --- /dev/null +++ b/src/nodes/QskGradientNode.cpp @@ -0,0 +1,166 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskGradientNode.h" +#include "QskGradient.h" +#include "QskSGNode.h" +#include "QskBoxRenderer.h" +#include "QskGradientMaterial.h" + +#include +#include + +QSK_QT_PRIVATE_BEGIN +#include +QSK_QT_PRIVATE_END + +Q_GLOBAL_STATIC( QSGVertexColorMaterial, qskMaterialColorVertex ) + +static inline QskGradient qskEffectiveGradient( const QskGradient& gradient ) +{ + if ( gradient.type() == QskGradient::Stops || gradient.isMonochrome() ) + { + // the shader for linear gradients is the fastest + QskGradient g; + g.setLinearDirection( Qt::Vertical ); + g.setStops( gradient.stops() ); + + return g; + } + + return gradient; +} + +class QskGradientNodePrivate final : public QSGGeometryNodePrivate +{ + public: + QskGradientNodePrivate() + : geometry( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 ) + { + } + + QSGGeometry geometry; + + QRectF rect; + QskHashValue gradientHash = 0; + + int gradientType = -1; +}; + +QskGradientNode::QskGradientNode() + : QSGGeometryNode( *new QskGradientNodePrivate ) +{ + Q_D( QskGradientNode ); + + setFlag( OwnsMaterial, true ); + setGeometry( &d->geometry ); +} + +QskGradientNode::~QskGradientNode() +{ +} + +void QskGradientNode::updateNode( + const QRectF& rect, const QskGradient& gradient ) +{ + Q_D( QskGradientNode ); + + if ( rect.isEmpty() || !gradient.isVisible() ) + { + d->rect = QRectF(); + d->gradientHash = 0; + QskSGNode::resetGeometry( this ); + + return; + } + + const auto effectiveGradient = qskEffectiveGradient( gradient ); + + const auto gradientHash = effectiveGradient.hash( 54228 ); + + const bool dirtyGradient = gradientHash != d->gradientHash; + const bool dirtyRect = rect != d->rect; + + if ( !( dirtyGradient || dirtyRect ) ) + return; + + d->gradientHash = gradientHash; + d->rect = rect; + + if ( QskBoxRenderer::isGradientSupported( effectiveGradient ) ) + { + if ( material() != qskMaterialColorVertex ) + { + setMaterial( qskMaterialColorVertex ); + setFlag( OwnsMaterial, false ); + + d->gradientType = -1; + } + + if ( d->geometry.attributeCount() == 1 ) + { + const QSGGeometry g( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 ); + memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) ); + } + } + else + { + if ( material() == qskMaterialColorVertex ) + { + setMaterial( nullptr ); + setFlag( OwnsMaterial, true ); + + d->gradientType = -1; + } + + if ( d->geometry.attributeCount() != 1 ) + { + const QSGGeometry g( QSGGeometry::defaultAttributes_Point2D(), 0 ); + memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) ); + } + } + + if ( material() == qskMaterialColorVertex ) + { + /* + Colors are added to the vertices, while the material does + not depend on the gradient at all + */ + if ( dirtyRect || dirtyGradient ) + { + QskBoxRenderer::renderRect( rect, effectiveGradient, d->geometry ); + markDirty( QSGNode::DirtyGeometry ); + } + } + else + { + /* + Colors are added by the shaders + + Monochrome gradients or QskGradient::Stops are supported by the + QskBoxRenderer. So we don't need to handle them here. + */ + if ( dirtyRect ) + { + QskBoxRenderer::renderRect( rect, d->geometry ); + markDirty( QSGNode::DirtyGeometry ); + } + + if ( dirtyGradient ) + { + const auto gradientType = effectiveGradient.type(); + + if ( 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/QskGradientNode.h b/src/nodes/QskGradientNode.h new file mode 100644 index 00000000..1f4c4f53 --- /dev/null +++ b/src/nodes/QskGradientNode.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_GRADIENT_NODE_H +#define QSK_GRADIENT_NODE_H + +#include "QskGlobal.h" +#include + +class QskGradient; +class QskGradientNodePrivate; + +class QSK_EXPORT QskGradientNode : public QSGGeometryNode +{ + public: + QskGradientNode(); + ~QskGradientNode() override; + + void updateNode( const QRectF&, const QskGradient& ); + + private: + Q_DECLARE_PRIVATE( QskGradientNode ) +}; + +#endif diff --git a/src/src.pro b/src/src.pro index dce7e265..fac37139 100644 --- a/src/src.pro +++ b/src/src.pro @@ -109,6 +109,7 @@ HEADERS += \ nodes/QskBoxRendererColorMap.h \ nodes/QskBoxShadowNode.h \ nodes/QskColorRamp.h \ + nodes/QskGradientNode.h \ nodes/QskGraphicNode.h \ nodes/QskPaintedNode.h \ nodes/QskPlainTextRenderer.h \ @@ -136,6 +137,7 @@ SOURCES += \ nodes/QskBoxRendererDEllipse.cpp \ nodes/QskBoxShadowNode.cpp \ nodes/QskColorRamp.cpp \ + nodes/QskGradientNode.cpp \ nodes/QskGraphicNode.cpp \ nodes/QskPaintedNode.cpp \ nodes/QskPlainTextRenderer.cpp \