QskBoxFillNode introduced

This commit is contained in:
Uwe Rathmann 2023-11-15 11:47:56 +01:00
parent 3b6967615c
commit 68cca6a53c
20 changed files with 418 additions and 500 deletions

View File

@ -108,6 +108,7 @@ list(APPEND HEADERS
nodes/QskBoxColorMap.h
nodes/QskBoxShadowNode.h
nodes/QskColorRamp.h
nodes/QskFillNode.h
nodes/QskGraphicNode.h
nodes/QskLinesNode.h
nodes/QskPaintedNode.h
@ -126,6 +127,10 @@ list(APPEND HEADERS
nodes/QskVertex.h
)
list(APPEND PRIVATE_HEADERS
nodes/QskFillNodePrivate.h
)
list(APPEND SOURCES
nodes/QskArcNode.cpp
nodes/QskBoxNode.cpp
@ -138,6 +143,7 @@ list(APPEND SOURCES
nodes/QskBoxGradientStroker.cpp
nodes/QskBoxShadowNode.cpp
nodes/QskColorRamp.cpp
nodes/QskFillNode.cpp
nodes/QskGraphicNode.cpp
nodes/QskLinesNode.cpp
nodes/QskPaintedNode.cpp

View File

@ -76,5 +76,6 @@ void QskBoxClipNode::setBox( const QRectF& rect,
*/
setClipRect( qskValidOrEmptyInnerRect( rect, border.widths() ) );
m_geometry.markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}

View File

@ -10,13 +10,7 @@
#include "QskBoxShapeMetrics.h"
#include "QskBoxBorderMetrics.h"
#include "QskBoxRenderer.h"
#include "QskSGNode.h"
#include <qsgflatcolormaterial.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
QSK_QT_PRIVATE_END
#include "QskFillNodePrivate.h"
static inline QskHashValue qskMetricsHash(
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics )
@ -27,14 +21,9 @@ static inline QskHashValue qskMetricsHash(
return borderMetrics.hash( hash );
}
class QskBoxFillNodePrivate final : public QSGGeometryNodePrivate
class QskBoxFillNodePrivate final : public QskFillNodePrivate
{
public:
QskBoxFillNodePrivate()
: geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
{
}
inline void resetValues()
{
rect = QRectF();
@ -46,19 +35,11 @@ class QskBoxFillNodePrivate final : public QSGGeometryNodePrivate
QskHashValue gradientHash = 0;
QskHashValue metricsHash = 0;
QSGGeometry geometry;
int gradientType = -1;
};
QskBoxFillNode::QskBoxFillNode()
: QSGGeometryNode( *new QskBoxFillNodePrivate )
: QskFillNode( *new QskBoxFillNodePrivate )
{
Q_D( QskBoxFillNode );
setGeometry( &d->geometry );
setMaterial( new QSGFlatColorMaterial() );
setFlag( QSGNode::OwnsMaterial, true );
}
void QskBoxFillNode::updateNode( const QRectF& rect, const QskGradient& gradient )
@ -75,7 +56,7 @@ void QskBoxFillNode::updateNode(
if ( rect.isEmpty() || !gradient.isVisible() )
{
d->resetValues();
QskSGNode::resetGeometry( this );
resetGeometry();
return;
}
@ -92,48 +73,22 @@ void QskBoxFillNode::updateNode(
if ( dirtyMetrics )
{
QskBox::renderFillGeometry( rect, shapeMetrics, borderMetrics, d->geometry );
QskBox::renderFillGeometry( rect, shapeMetrics, borderMetrics, *geometry() );
markDirty( QSGNode::DirtyGeometry );
geometry()->markVertexDataDirty();
}
if ( gradient.isMonochrome() )
{
if ( dirtyColors )
{
if ( material() == nullptr || d->gradientType >= 0 )
{
setMaterial( new QSGFlatColorMaterial() );
d->gradientType = -1;
}
const auto color = gradient.startColor().toRgb();
auto mat = static_cast< QSGFlatColorMaterial* >( material() );
if ( mat->color() != color )
{
mat->setColor( color );
markDirty( QSGNode::DirtyMaterial );
}
}
setColoring( gradient.startColor().toRgb() );
}
else
{
// dirtyMetrics: the shader also depends on the target rectangle !
if ( dirtyColors || dirtyMetrics )
{
const auto effectiveGradient = gradient.effectiveGradient();
const auto gradientType = effectiveGradient.type();
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 );
}
setColoring( rect, gradient.effectiveGradient() );
}
}

View File

@ -7,7 +7,7 @@
#define QSK_BOX_FILL_NODE_H
#include "QskGlobal.h"
#include <qsgnode.h>
#include "QskFillNode.h"
class QskGradient;
class QskBoxShapeMetrics;
@ -15,8 +15,10 @@ class QskBoxBorderMetrics;
class QskBoxFillNodePrivate;
class QSK_EXPORT QskBoxFillNode : public QSGGeometryNode
class QSK_EXPORT QskBoxFillNode : public QskFillNode
{
using Inherited = QskFillNode;
public:
QskBoxFillNode();

View File

@ -10,16 +10,7 @@
#include "QskBoxShapeMetrics.h"
#include "QskGradient.h"
#include "QskGradientDirection.h"
#include <qglobalstatic.h>
#include <qsgflatcolormaterial.h>
#include <qsgvertexcolormaterial.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
QSK_QT_PRIVATE_END
Q_GLOBAL_STATIC( QSGVertexColorMaterial, qskMaterialColorVertex )
#include "QskFillNodePrivate.h"
static inline QskHashValue qskMetricsHash(
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics )
@ -55,34 +46,21 @@ static inline QskGradient qskEffectiveGradient( const QskGradient& gradient )
#endif
class QskBoxRectangleNodePrivate final : public QSGGeometryNodePrivate
class QskBoxRectangleNodePrivate final : public QskFillNodePrivate
{
public:
QskBoxRectangleNodePrivate()
: geometry( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 )
{
}
QskHashValue metricsHash = 0;
QskHashValue colorsHash = 0;
QRectF rect;
QSGGeometry geometry;
};
QskBoxRectangleNode::QskBoxRectangleNode()
: QSGGeometryNode( *new QskBoxRectangleNodePrivate )
: QskFillNode( *new QskBoxRectangleNodePrivate )
{
Q_D( QskBoxRectangleNode );
setMaterial( qskMaterialColorVertex );
setGeometry( &d->geometry );
}
QskBoxRectangleNode::~QskBoxRectangleNode()
{
if ( material() != qskMaterialColorVertex )
delete material();
}
void QskBoxRectangleNode::updateNode(
@ -129,7 +107,7 @@ void QskBoxRectangleNode::updateNode( const QRectF& rect,
if ( rect.isEmpty() )
{
d->geometry.allocate( 0 );
resetGeometry();
return;
}
@ -148,7 +126,7 @@ void QskBoxRectangleNode::updateNode( const QRectF& rect,
if ( !hasBorder && !hasFill )
{
d->geometry.allocate( 0 );
resetGeometry();
return;
}
@ -167,6 +145,8 @@ void QskBoxRectangleNode::updateNode( const QRectF& rect,
}
}
auto coloring = QskFillNode::Polychrome;
#if 0
/*
Always using the same material result in a better batching
@ -175,74 +155,40 @@ void QskBoxRectangleNode::updateNode( const QRectF& rect,
but for the moment we go with performance.
*/
bool maybeFlat = true;
if ( maybeFlat )
if ( !( hasFill && hasBorder ) )
{
if ( ( hasFill && hasBorder ) ||
( hasFill && !isFillMonochrome ) ||
( hasBorder && !isBorderMonochrome ) )
if ( ( hasFill && isFillMonochrome )
|| ( hasBorder && !isBorderMonochrome )
{
maybeFlat = false;
coloring = QskFillNode::Monochrome;
}
}
#else
bool maybeFlat = false;
#endif
if ( !maybeFlat )
auto& geometry = *this->geometry();
if ( coloring == QskFillNode::Polychrome )
{
setMonochrome( false );
setColoring( coloring );
QskBox::renderBox( d->rect, shape, borderMetrics,
borderColors, fillGradient, *geometry() );
borderColors, fillGradient, geometry );
}
else
{
// all is done with one color
setMonochrome( true );
auto* flatMaterial = static_cast< QSGFlatColorMaterial* >( material() );
if ( hasFill )
{
flatMaterial->setColor( fillGradient.rgbStart() );
setColoring( fillGradient.rgbStart() );
QskBox::renderFillGeometry(
d->rect, shape, QskBoxBorderMetrics(), *geometry() );
d->rect, shape, QskBoxBorderMetrics(), geometry );
}
else
{
flatMaterial->setColor( borderColors.left().rgbStart() );
setColoring( borderColors.left().rgbStart() );
QskBox::renderBorderGeometry(
d->rect, shape, borderMetrics, *geometry() );
d->rect, shape, borderMetrics, geometry );
}
}
}
void QskBoxRectangleNode::setMonochrome( bool on )
{
const auto material = this->material();
if ( on == ( material != qskMaterialColorVertex ) )
return;
Q_D( QskBoxRectangleNode );
d->geometry.allocate( 0 );
if ( on )
{
setMaterial( new QSGFlatColorMaterial() );
const QSGGeometry g( QSGGeometry::defaultAttributes_Point2D(), 0 );
memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) );
}
else
{
setMaterial( qskMaterialColorVertex );
delete material;
const QSGGeometry g( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 );
memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) );
}
geometry.markVertexDataDirty();
}

View File

@ -7,7 +7,7 @@
#define QSK_BOX_RECTANGLE_NODE_H
#include "QskGlobal.h"
#include <qsgnode.h>
#include "QskFillNode.h"
class QskBoxShapeMetrics;
class QskBoxBorderMetrics;
@ -16,8 +16,10 @@ class QskGradient;
class QskBoxRectangleNodePrivate;
class QSK_EXPORT QskBoxRectangleNode : public QSGGeometryNode
class QSK_EXPORT QskBoxRectangleNode : public QskFillNode
{
using Inherited = QskFillNode;
public:
QskBoxRectangleNode();
~QskBoxRectangleNode() override;
@ -32,8 +34,6 @@ class QSK_EXPORT QskBoxRectangleNode : public QSGGeometryNode
const QskBoxShapeMetrics&, const QskGradient& );
private:
void setMonochrome( bool on );
Q_DECLARE_PRIVATE( QskBoxRectangleNode )
};

View File

@ -281,6 +281,7 @@ void QskBoxShadowNode::setShadowData(
QSGGeometry::updateTexturedRectGeometry(
&d->geometry, d->rect, QRectF( -0.5, -0.5, 1.0, 1.0 ) );
d->geometry.markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
QVector2D aspect( 1.0, 1.0 );

153
src/nodes/QskFillNode.cpp Normal file
View File

@ -0,0 +1,153 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskFillNode.h"
#include "QskGradientMaterial.h"
#include "QskFillNodePrivate.h"
#include "QskSGNode.h"
#include <qsgflatcolormaterial.h>
#include <qsgvertexcolormaterial.h>
#include <qglobalstatic.h>
Q_GLOBAL_STATIC( QSGVertexColorMaterial, qskMaterialColorVertex )
static inline QskGradient::Type qskGradientType( QskFillNode::Coloring coloring )
{
const auto type = QskGradient::Linear + coloring - QskFillNode::Linear;
return static_cast< QskGradient::Type >( type );
}
static inline QskFillNode::Coloring qskColoring( QskGradient::Type type )
{
const auto coloring = QskFillNode::Linear + type - QskGradient::Linear;
return static_cast< QskFillNode::Coloring >( coloring );
}
QskFillNode::QskFillNode()
: QskFillNode( *new QskFillNodePrivate )
{
}
QskFillNode::QskFillNode( QskFillNodePrivate& dd )
: QSGGeometryNode( dd )
{
setGeometry( &dd.geometry );
setMaterial( qskMaterialColorVertex );
setFlag( QSGNode::OwnsMaterial, false );
}
QskFillNode::~QskFillNode()
{
}
void QskFillNode::resetGeometry()
{
QskSGNode::resetGeometry( this );
}
void QskFillNode::setColoring( Coloring coloring )
{
Q_D( QskFillNode );
if ( coloring == d->coloring )
return;
d->coloring = coloring;
switch( coloring )
{
case Monochrome:
{
setMaterial( new QSGFlatColorMaterial() );
break;
}
case Polychrome:
{
setMaterial( qskMaterialColorVertex );
break;
}
/*
QSGDefaultInternalRectangleNode is using QSGSmoothColorMaterial.
Can we do something useful with it too ? TODO ...
*/
default:
{
const auto gradientType = qskGradientType( coloring );
setMaterial( QskGradientMaterial::createMaterial( gradientType ) );
}
}
if ( material() == qskMaterialColorVertex )
{
/*
All color information is stored in the geometry and we can share
the material regardless of the specific colors.
As nodes with the same material can be batched it might make sense
to use this type of coloring for monochrome fillings: memory vs. performance.
*/
setFlag( QSGNode::OwnsMaterial, false ); // shared: do not delete
if ( !isGeometryColored() )
{
const QSGGeometry g( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 );
memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) );
}
}
else
{
setFlag( QSGNode::OwnsMaterial, true );
if ( isGeometryColored() )
{
const QSGGeometry g( QSGGeometry::defaultAttributes_Point2D(), 0 );
memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) );
}
}
}
QskFillNode::Coloring QskFillNode::coloring() const
{
return d_func()->coloring;
}
void QskFillNode::setColoring( const QColor& color )
{
setColoring( Monochrome );
auto mat = static_cast< QSGFlatColorMaterial* >( material() );
if ( mat->color() != color )
{
mat->setColor( color );
markDirty( QSGNode::DirtyMaterial );
}
}
void QskFillNode::setColoring( const QRectF& rect, const QskGradient& gradient )
{
if ( gradient.isMonochrome() )
{
setColoring( gradient.startColor().toRgb() );
}
else
{
const auto effectiveGradient = gradient.effectiveGradient();
setColoring( qskColoring( effectiveGradient.type() ) );
auto mat = static_cast< QskGradientMaterial* >( material() );
if ( mat->updateGradient( rect, effectiveGradient ) )
markDirty( QSGNode::DirtyMaterial );
}
}
bool QskFillNode::isGeometryColored() const
{
return d_func()->geometry.attributeCount() != 1;
}

50
src/nodes/QskFillNode.h Normal file
View File

@ -0,0 +1,50 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_FILL_NODE_H
#define QSK_FILL_NODE_H
#include "QskGlobal.h"
#include <qsgnode.h>
class QskFillNodePrivate;
class QskGradient;
class QSK_EXPORT QskFillNode : public QSGGeometryNode
{
using Inherited = QSGGeometryNode;
public:
enum Coloring
{
Monochrome,
Polychrome,
Linear,
Radial,
Conic
};
QskFillNode();
~QskFillNode() override;
void resetGeometry();
void setColoring( Coloring );
Coloring coloring() const;
void setColoring( const QColor& );
void setColoring( const QRectF&, const QskGradient& );
bool isGeometryColored() const;
protected:
QskFillNode( QskFillNodePrivate& );
private:
Q_DECLARE_PRIVATE( QskFillNode )
};
#endif

View File

@ -0,0 +1,32 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_FILL_NODE_PRIVATE_H
#define QSK_FILL_NODE_PRIVATE_H
#include "QskGlobal.h"
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
QSK_QT_PRIVATE_END
class QskFillNode;
class QskFillNodePrivate : public QSGGeometryNodePrivate
{
public:
inline QskFillNodePrivate()
: geometry( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 )
{
}
private:
friend class QskFillNode;
QSGGeometry geometry;
QskFillNode::Coloring coloring = QskFillNode::Polychrome;
};
#endif

View File

@ -121,7 +121,6 @@ class QskLinesNodePrivate final : public QSGGeometryNodePrivate
: geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
{
geometry.setDrawingMode( QSGGeometry::DrawLines );
geometry.setVertexDataPattern( QSGGeometry::StaticPattern );
}
inline qreal round( bool isHorizontal, qreal v ) const
@ -298,6 +297,7 @@ void QskLinesNode::updateLines( const QColor& color,
{
updateGeometry( stippleMetrics, transform, count, lines );
d->geometry.markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
d->dirty = false;
}
@ -336,6 +336,7 @@ void QskLinesNode::updateGrid( const QColor& color,
{
updateGeometry( stippleMetrics, transform, rect, xValues, yValues );
d->geometry.markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
d->dirty = false;
}
@ -388,7 +389,6 @@ void QskLinesNode::updateGeometry( const QskStippleMetrics& stippleMetrics,
count, lines, stippleMetrics, points );
}
Q_ASSERT( geom.vertexCount() == ( points - geom.vertexDataAsPoint2D() ) );
}
@ -542,3 +542,46 @@ QSGGeometry::Point2D* QskLinesNode::setSolidLines(
return reinterpret_cast< QSGGeometry::Point2D* >( lines );
}
void QskLinesNode::updatePolygon( const QColor& color, qreal lineWidth,
const QTransform& transform, const QPolygonF& polygon )
{
if ( polygon.isEmpty() || !color.isValid() || ( color.alpha() == 0 ) )
{
QskSGNode::resetGeometry( this );
return;
}
Q_D( QskLinesNode );
if ( true ) // for the moment we always update the geometry. TODO ...
{
d->geometry.allocate( polygon.count() + 1 );
auto points = d->geometry.vertexDataAsPoint2D();
if ( transform.isIdentity() )
{
for ( int i = 0; i < polygon.count(); i++ )
{
const auto& pos = polygon[i];
points[i].set( pos.x(), pos.y() );
}
}
else
{
for ( int i = 0; i < polygon.count(); i++ )
{
const auto pos = transform.map( polygon[i] );
points[i].set( pos.x(), pos.y() );
}
}
points[ polygon.count() ] = points[0];
d->geometry.markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}
d->setLineAttributes( this, color, lineWidth );
}

View File

@ -16,6 +16,7 @@ class QskStippleMetrics;
class QTransform;
class QPointF;
class QLineF;
class QPolygonF;
class QQuickItem;
class QskLinesNodePrivate;
@ -26,6 +27,8 @@ class QskLinesNodePrivate;
*/
class QSK_EXPORT QskLinesNode : public QSGGeometryNode
{
using Inherited = QSGGeometryNode;
public:
QskLinesNode();
~QskLinesNode() override;
@ -53,6 +56,9 @@ class QSK_EXPORT QskLinesNode : public QSGGeometryNode
void updateLines( const QColor&, qreal lineWidth,
const QskStippleMetrics&, const QTransform&, const QVector< QLineF >& );
void updatePolygon( const QColor&, qreal lineWidth,
const QTransform&, const QPolygonF& );
private:
void updateLines( const QColor&, qreal lineWidth, const QskStippleMetrics&,
const QTransform&, int count, const QLineF* );

View File

@ -5,28 +5,13 @@
#include "QskRectangleNode.h"
#include "QskGradient.h"
#include "QskSGNode.h"
#include "QskBoxRenderer.h"
#include "QskBoxShapeMetrics.h"
#include "QskGradientMaterial.h"
#include "QskFillNodePrivate.h"
#include <qglobalstatic.h>
#include <qsgvertexcolormaterial.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
QSK_QT_PRIVATE_END
Q_GLOBAL_STATIC( QSGVertexColorMaterial, qskMaterialColorVertex )
class QskRectangleNodePrivate final : public QSGGeometryNodePrivate
class QskRectangleNodePrivate final : public QskFillNodePrivate
{
public:
QskRectangleNodePrivate()
: geometry( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 )
{
}
inline void resetValues()
{
rect = QRectF();
@ -35,24 +20,16 @@ class QskRectangleNodePrivate final : public QSGGeometryNodePrivate
metricsHash = 0;
}
QSGGeometry geometry;
QRectF rect;
QskBoxShapeMetrics shape;
QskHashValue gradientHash = 0;
QskHashValue metricsHash = 0;
int gradientType = -1;
};
QskRectangleNode::QskRectangleNode()
: QSGGeometryNode( *new QskRectangleNodePrivate )
: QskFillNode( *new QskRectangleNodePrivate )
{
Q_D( QskRectangleNode );
setFlag( OwnsMaterial, true );
setGeometry( &d->geometry );
}
QskRectangleNode::~QskRectangleNode()
@ -73,7 +50,7 @@ void QskRectangleNode::updateNode(
if ( rect.isEmpty() || !gradient.isVisible() )
{
d->resetValues();
QskSGNode::resetGeometry( this );
resetGeometry();
return;
}
@ -97,39 +74,8 @@ void QskRectangleNode::updateNode(
if ( QskBox::isGradientSupported( effectiveShape, effectiveGradient ) )
{
if ( material() != qskMaterialColorVertex )
{
setMaterial( qskMaterialColorVertex );
setFlag( OwnsMaterial, false );
setColoring( Polychrome );
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
@ -137,39 +83,23 @@ void QskRectangleNode::updateNode(
if ( dirtyMetrics || dirtyColors )
{
QskBox::renderBox( rect,
effectiveShape, effectiveGradient, d->geometry );
effectiveShape, effectiveGradient, *geometry() );
geometry()->markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}
}
else
{
/*
Colors are added by the shaders
if ( dirtyColors || dirtyMetrics )
setColoring( rect, effectiveGradient );
Monochrome gradients or QskGradient::Stops are supported by the
QskBoxRenderer. So we don't need to handle them here.
*/
if ( dirtyMetrics )
{
QskBox::renderFillGeometry( rect, effectiveShape, d->geometry );
QskBox::renderFillGeometry( rect, effectiveShape, *geometry() );
geometry()->markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}
// dirtyMetrics: the shader also depends on the target rectangle !
if ( dirtyColors || dirtyMetrics )
{
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 );
}
}
}

View File

@ -7,7 +7,7 @@
#define QSK_RECTANGLE_NODE_H
#include "QskGlobal.h"
#include <qsgnode.h>
#include "QskFillNode.h"
class QskGradient;
class QskBoxShapeMetrics;
@ -15,11 +15,11 @@ class QskRectangleNodePrivate;
/*
QskRectangleNode is for rounded rectangles without a border.
Depending on the type of gradient it uses a different
material/geometry combination.
*/
class QSK_EXPORT QskRectangleNode : public QSGGeometryNode
class QSK_EXPORT QskRectangleNode : public QskFillNode
{
using Inherited = QskFillNode;
public:
QskRectangleNode();
~QskRectangleNode() override;

View File

@ -173,9 +173,19 @@ void QskSGNode::resetGeometry( QSGGeometryNode* node )
{
if ( auto g = node->geometry() )
{
if ( g->vertexCount() > 0 || g->indexCount() > 0 )
const bool hasVertices = g->vertexCount() > 0;
const bool hasIndexes = g->indexCount() > 0;
if ( hasVertices || hasIndexes )
{
g->allocate( 0, 0 );
if ( hasVertices )
g->markVertexDataDirty();
if ( hasIndexes )
g->markIndexDataDirty();
node->markDirty( QSGNode::DirtyGeometry );
}
}

View File

@ -4,15 +4,11 @@
*****************************************************************************/
#include "QskShapeNode.h"
#include "QskGradientMaterial.h"
#include "QskGradient.h"
#include "QskGradientDirection.h"
#include "QskSGNode.h"
#include <qsgflatcolormaterial.h>
#include "QskFillNodePrivate.h"
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
#include <private/qvectorpath_p.h>
#include <private/qtriangulator_p.h>
QSK_QT_PRIVATE_END
@ -59,18 +55,9 @@ static void qskUpdateGeometry( const QPainterPath& path,
#endif
}
class QskShapeNodePrivate final : public QSGGeometryNodePrivate
class QskShapeNodePrivate final : public QskFillNodePrivate
{
public:
QskShapeNodePrivate()
: geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
{
geometry.setDrawingMode( QSGGeometry::DrawTriangles );
}
QSGGeometry geometry;
int gradientType = -1;
/*
Is there a better way to find out if the path has changed
beside storing a copy ( even, when internally with Copy On Write ) ?
@ -80,13 +67,10 @@ class QskShapeNodePrivate final : public QSGGeometryNodePrivate
};
QskShapeNode::QskShapeNode()
: QSGGeometryNode( *new QskShapeNodePrivate )
: QskFillNode( *new QskShapeNodePrivate )
{
Q_D( QskShapeNode );
setGeometry( &d->geometry );
setMaterial( new QSGFlatColorMaterial() );
setFlag( QSGNode::OwnsMaterial, true );
setColoring( Monochrome );
geometry()->setDrawingMode( QSGGeometry::DrawTriangles );
}
QskShapeNode::~QskShapeNode()
@ -102,58 +86,21 @@ void QskShapeNode::updateNode( const QPainterPath& path,
{
d->path = QPainterPath();
d->transform = QTransform();
QskSGNode::resetGeometry( this );
resetGeometry();
return;
}
setColoring( rect, gradient );
if ( ( transform != d->transform ) || ( path != d->path ) )
{
d->path = path;
d->transform = transform;
qskUpdateGeometry( path, transform, d->geometry );
qskUpdateGeometry( path, transform, *geometry() );
geometry()->markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}
if ( gradient.isMonochrome() )
{
if ( material() == nullptr || d->gradientType >= 0 )
{
setMaterial( new QSGFlatColorMaterial() );
d->gradientType = -1;
}
const auto color = gradient.startColor().toRgb();
/*
We might want to use QSGVertexColorMaterial to improve the "batchability"
as this material does not depend on the specific colors. It could even be
batched with QskBoxNodes, that are usually using QSGVertexColorMaterial as well.
However we would have to store the color information for each vertex.
For the moment we prefer less memory over better "batchability".
*/
auto mat = static_cast< QSGFlatColorMaterial* >( material() );
if ( mat->color() != color )
{
mat->setColor( color );
markDirty( QSGNode::DirtyMaterial );
}
}
else
{
const auto effectiveGradient = gradient.effectiveGradient();
const auto gradientType = effectiveGradient.type();
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 );
}
}

View File

@ -7,7 +7,7 @@
#define QSK_SHAPE_NODE_H
#include "QskGlobal.h"
#include <qsgnode.h>
#include "QskFillNode.h"
class QskGradient;
class QColor;
@ -15,8 +15,10 @@ class QPainterPath;
class QskShapeNodePrivate;
class QSK_EXPORT QskShapeNode : public QSGGeometryNode
class QSK_EXPORT QskShapeNode : public QskFillNode
{
using Inherited = QskFillNode;
public:
QskShapeNode();
~QskShapeNode() override;

View File

@ -5,145 +5,64 @@
#include "QskStrokeNode.h"
#include "QskVertex.h"
#include "QskGradient.h"
#include <qsgflatcolormaterial.h>
#include <qsgvertexcolormaterial.h>
#include <qpainterpath.h>
#include <qpolygon.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
#include <private/qtriangulatingstroker_p.h>
QSK_QT_PRIVATE_END
Q_GLOBAL_STATIC( QSGVertexColorMaterial, qskMaterialColorVertex )
static inline void qskMapPolygon( const QPolygonF& polygon,
const QTransform& transform, const QColor& color, QSGGeometry& geometry )
static inline bool qskIsPenVisible( const QPen& pen )
{
const QskVertex::Color c( color );
if ( pen.style() == Qt::NoPen )
return false;
auto p = geometry.vertexDataAsColoredPoint2D();
if ( transform.isIdentity() )
if ( pen.brush().gradient() )
{
for ( int i = 0; i < polygon.count(); i++ )
{
const auto& pos = polygon[i];
p[i].set( pos.x(), pos.y(), c.r, c.g, c.b, c.a );
}
// TODO ...
}
else
{
for ( int i = 0; i < polygon.count(); i++ )
{
const auto pos = transform.map( polygon[i] );
p[i].set( pos.x(), pos.y(), c.r, c.g, c.b, c.a );
}
if ( pen.color().isValid() || ( pen.color().alpha() == 0 ) )
return false;
}
return true;
}
static inline void qskMapPolygon( const QPolygonF& polygon,
const QTransform& transform, QSGGeometry& geometry )
{
auto p = geometry.vertexDataAsPoint2D();
if ( transform.isIdentity() )
{
for ( int i = 0; i < polygon.count(); i++ )
{
const auto& pos = polygon[i];
p[i].set( pos.x(), pos.y() );
}
}
else
{
for ( int i = 0; i < polygon.count(); i++ )
{
const auto pos = transform.map( polygon[i] );
p[i].set( pos.x(), pos.y() );
}
}
}
class QskStrokeNodePrivate final : public QSGGeometryNodePrivate
{
public:
QskStrokeNodePrivate()
: geometry( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 )
{
}
QSGGeometry geometry;
};
QskStrokeNode::QskStrokeNode()
: QSGGeometryNode( *new QskStrokeNodePrivate )
{
Q_D( QskStrokeNode );
setGeometry( &d->geometry );
setMaterial( qskMaterialColorVertex );
}
QskStrokeNode::~QskStrokeNode() = default;
void QskStrokeNode::setRenderHint( RenderHint renderHint )
{
Q_D( QskStrokeNode );
const auto material = this->material();
if ( renderHint == Colored )
{
if ( material != qskMaterialColorVertex )
{
setMaterial( qskMaterialColorVertex );
delete material;
const QSGGeometry g( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 );
memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) );
}
}
else
{
if ( material == qskMaterialColorVertex )
{
setMaterial( new QSGFlatColorMaterial() );
const QSGGeometry g( QSGGeometry::defaultAttributes_Point2D(), 0 );
memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) );
}
}
}
QskStrokeNode::RenderHint QskStrokeNode::renderHint() const
{
return ( material() == qskMaterialColorVertex ) ? Colored : Flat;
}
void QskStrokeNode::updateNode( const QPainterPath& path, const QPen& pen )
{
updateNode( path, QTransform(), pen );
}
void QskStrokeNode::updateNode(
const QPainterPath& path, const QTransform& transform, const QPen& pen )
const QPainterPath& path, const QTransform& transform, const QPen& pen )
{
Q_D( QskStrokeNode );
if ( path.isEmpty() || ( pen.style() == Qt::NoPen ) ||
!pen.color().isValid() || ( pen.color().alpha() == 0 ) )
if ( path.isEmpty() || !qskIsPenVisible( pen ) )
{
if ( d->geometry.vertexCount() > 0 )
{
d->geometry.allocate( 0 );
markDirty( QSGNode::DirtyGeometry );
}
resetGeometry();
return;
}
if ( auto qGradient = pen.brush().gradient() )
{
const auto r = transform.mapRect( path.boundingRect() );
QskGradient gradient( *qGradient );
gradient.setStretchMode( QskGradient::StretchToSize );
setColoring( r, gradient );
}
else
setColoring( pen.color() );
if ( true ) // For the moment we always update the geometry. TODO ...
{
/*
@ -176,7 +95,8 @@ void QskStrokeNode::updateNode(
constexpr QRectF clipRect; // empty rect: no clipping
QDashedStrokeProcessor dashStroker;
dashStroker.process( qtVectorPathForPath( scaledPath ), effectivePen, clipRect, {} );
dashStroker.process( qtVectorPathForPath( scaledPath ),
effectivePen, clipRect, {} );
const QVectorPath dashedVectorPath( dashStroker.points(),
dashStroker.elementCount(), dashStroker.elementTypes(), 0 );
@ -184,18 +104,20 @@ void QskStrokeNode::updateNode(
stroker.process( dashedVectorPath, effectivePen, {}, {} );
}
// 2 vertices for each point
d->geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
d->geometry.allocate( stroker.vertexCount() / 2 );
auto& geometry = *this->geometry();
if ( material() == qskMaterialColorVertex )
// 2 vertices for each point
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
geometry.allocate( stroker.vertexCount() / 2 );
if ( isGeometryColored() )
{
const QskVertex::Color c( pen.color() );
const auto v = stroker.vertices();
auto points = d->geometry.vertexDataAsColoredPoint2D();
auto points = geometry.vertexDataAsColoredPoint2D();
for ( int i = 0; i < d->geometry.vertexCount(); i++ )
for ( int i = 0; i < geometry.vertexCount(); i++ )
{
const auto j = 2 * i;
points[i].set( v[j], v[j + 1], c.r, c.g, c.b, c.a );
@ -203,80 +125,11 @@ void QskStrokeNode::updateNode(
}
else
{
memcpy( d->geometry.vertexData(), stroker.vertices(),
memcpy( geometry.vertexData(), stroker.vertices(),
stroker.vertexCount() * sizeof( float ) );
}
geometry.markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}
if ( material() != qskMaterialColorVertex )
{
const auto color = pen.color().toRgb();
auto flatMaterial = static_cast< QSGFlatColorMaterial* >( material() );
if ( flatMaterial->color() != color )
{
flatMaterial->setColor( color );
markDirty( QSGNode::DirtyMaterial );
}
}
}
void QskStrokeNode::updateNode( const QPolygonF& polygon,
qreal lineWidth, const QColor& color )
{
updateNode( polygon, QTransform(), lineWidth, color );
}
/*
For polygons with a small lineWidth ( < 2 ) or a line without
connections we might get away with a simple and fast implementation
using DrawLineStrip/DrawLineLoop
*/
void QskStrokeNode::updateNode( const QPolygonF& polygon,
const QTransform& transform, qreal lineWidth, const QColor& color )
{
Q_D( QskStrokeNode );
if ( polygon.isEmpty() || !color.isValid() || ( color.alpha() == 0 ) )
{
if ( d->geometry.vertexCount() > 0 )
{
d->geometry.allocate( 0 );
markDirty( QSGNode::DirtyGeometry );
}
return;
}
d->geometry.setDrawingMode( QSGGeometry::DrawLineStrip );
const float lineWidthF = lineWidth;
if( lineWidthF != d->geometry.lineWidth() )
d->geometry.setLineWidth( lineWidthF );
if ( true ) // TODO
{
d->geometry.allocate( polygon.count() );
if ( material() == qskMaterialColorVertex )
{
qskMapPolygon( polygon, transform, color, d->geometry );
markDirty( QSGNode::DirtyGeometry );
}
else
{
qskMapPolygon( polygon, transform, d->geometry );
markDirty( QSGNode::DirtyGeometry );
auto flatMaterial = static_cast< QSGFlatColorMaterial* >( material() );
if ( flatMaterial->color() != color )
{
flatMaterial->setColor( color );
markDirty( QSGNode::DirtyMaterial );
}
}
}
}

View File

@ -7,44 +7,26 @@
#define QSK_STROKE_NODE_H
#include "QskGlobal.h"
#include <qsgnode.h>
#include "QskFillNode.h"
class QPen;
class QPainterPath;
class QPolygonF;
class QskStrokeNodePrivate;
class QSK_EXPORT QskStrokeNode : public QSGGeometryNode
class QSK_EXPORT QskStrokeNode : public QskFillNode
{
using Inherited = QskFillNode;
public:
QskStrokeNode();
~QskStrokeNode() override;
/*
We only support monochrome pens ( QPen::color() ) and using a
QSGFlatColorMaterial is good enough. However QSGVertexColorMaterial
usually allows better batching. So Flat vs. Colored is a tradeoff
between memory and performance.
*/
enum RenderHint
{
Flat,
Colored
};
void setRenderHint( RenderHint );
RenderHint renderHint() const;
void updateNode( const QPainterPath&, const QPen& );
void updateNode( const QPainterPath&, const QTransform&, const QPen& );
void updateNode( const QPolygonF&, qreal lineWidth, const QColor& );
void updateNode( const QPolygonF&, const QTransform&,
void updateNode0( const QPolygonF&, qreal lineWidth, const QColor& );
void updateNode0( const QPolygonF&, const QTransform&,
qreal lineWidth, const QColor& );
private:
Q_DECLARE_PRIVATE( QskStrokeNode )
};
#endif

View File

@ -22,7 +22,6 @@ class QskTickmarksNodePrivate final : public QSGGeometryNodePrivate
: geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
{
geometry.setDrawingMode( QSGGeometry::DrawLines );
geometry.setVertexDataPattern( QSGGeometry::StaticPattern );
}
QSGGeometry geometry;