Merge branch 'master' into features/arcrenderer

This commit is contained in:
Uwe Rathmann 2024-09-26 10:59:24 +02:00
commit 5f796bed48
12 changed files with 109 additions and 49 deletions

View File

@ -7,6 +7,7 @@
#include <QskGradient.h> #include <QskGradient.h>
#include <QskGradientDirection.h> #include <QskGradientDirection.h>
#include <QskBoxRenderer.h>
QSK_QT_PRIVATE_BEGIN QSK_QT_PRIVATE_BEGIN
@ -54,10 +55,10 @@ namespace
{ {
QQuickShapeGradient* shapeGradient = nullptr; QQuickShapeGradient* shapeGradient = nullptr;
auto effectiveGradient = gradient.effectiveGradient(); auto effectiveGradient = QskBoxRenderer::effectiveGradient( gradient );
effectiveGradient.stretchTo( rect ); effectiveGradient.stretchTo( rect );
switch( static_cast< int >( gradient.type() ) ) switch( static_cast< int >( effectiveGradient.type() ) )
{ {
case QskGradient::Linear: case QskGradient::Linear:
{ {

View File

@ -722,21 +722,6 @@ void QskGradient::resetDirection()
m_values[0] = m_values[1] = m_values[2] = m_values[3] = m_values[4] = 0.0; m_values[0] = m_values[1] = m_values[2] = m_values[3] = m_values[4] = 0.0;
} }
QskGradient QskGradient::effectiveGradient() const
{
if ( ( m_type == QskGradient::Stops ) || isMonochrome() )
{
// the shader for linear gradients is the fastest
QskGradient g = *this;
g.setDirection( QskGradient::Linear );
return g;
}
return *this;
}
QGradient QskGradient::toQGradient() const QGradient QskGradient::toQGradient() const
{ {
QGradient g; QGradient g;

View File

@ -152,8 +152,6 @@ class QSK_EXPORT QskGradient
QskGradient stretchedTo( const QSizeF& ) const; QskGradient stretchedTo( const QSizeF& ) const;
QskGradient stretchedTo( const QRectF& ) const; QskGradient stretchedTo( const QRectF& ) const;
QskGradient effectiveGradient() const;
static QVariant interpolate( const QskGradient&, static QVariant interpolate( const QskGradient&,
const QskGradient&, qreal progress ); const QskGradient&, qreal progress );

View File

@ -90,7 +90,7 @@ int QskSelectionSubWindow::selectedRow() const
QString QskSelectionSubWindow::selectedEntry() const QString QskSelectionSubWindow::selectedEntry() const
{ {
if ( auto listBox = qskListBox( this ) ) if ( auto listBox = qskListBox( this ) )
listBox->selectedEntry(); return listBox->selectedEntry();
return QString(); return QString();
} }

View File

@ -93,7 +93,7 @@ int QskSelectionWindow::selectedRow() const
QString QskSelectionWindow::selectedEntry() const QString QskSelectionWindow::selectedEntry() const
{ {
if ( auto listBox = qskListBox( this ) ) if ( auto listBox = qskListBox( this ) )
listBox->selectedEntry(); return listBox->selectedEntry();
return QString(); return QString();
} }

View File

@ -104,8 +104,17 @@ void QskArcRenderNode::updateFilling( const QRectF& rect,
return; return;
} }
const bool coloredGeometry = hasHint( PreferColoredGeometry ) bool coloredGeometry = hasHint( PreferColoredGeometry );
&& QskArcRenderer::isGradientSupported( rect, metrics, gradient ); if ( coloredGeometry )
{
// not all gradients are supported by the renderer
coloredGeometry = QskArcRenderer::isGradientSupported( rect, metrics, gradient );
}
else
{
// QskGradient::Stops is specific for QskArcRenderer
coloredGeometry = ( gradient.type() == QskGradient::Stops );
}
bool dirtyGeometry = d->updateMetrics( rect, metrics, radial, borderWidth ); bool dirtyGeometry = d->updateMetrics( rect, metrics, radial, borderWidth );
bool dirtyMaterial = d->updateColors( QColor(), gradient ); bool dirtyMaterial = d->updateColors( QColor(), gradient );

View File

@ -458,6 +458,7 @@ bool QskArcRenderer::isGradientSupported( const QRectF& rect,
} }
case QskGradient::Conic: case QskGradient::Conic:
{ {
#if 0
const auto direction = gradient.conicDirection(); const auto direction = gradient.conicDirection();
if ( direction.center() == rect.center() ) if ( direction.center() == rect.center() )
{ {
@ -470,6 +471,7 @@ bool QskArcRenderer::isGradientSupported( const QRectF& rect,
*/ */
} }
} }
#endif
return false; return false;
} }
@ -572,7 +574,7 @@ void QskArcRenderer::setBorderLines( const QRectF& rect,
return; return;
} }
const Renderer renderer( rect, metrics, radial, QskGradient(), 0 ); const Renderer renderer( rect, metrics, radial, QskGradient(), QskRgb::Black );
const auto lines = qskAllocateLines( geometry, renderer.borderCount() ); const auto lines = qskAllocateLines( geometry, renderer.borderCount() );
if ( lines ) if ( lines )

View File

@ -103,7 +103,7 @@ void QskBoxRectangleNode::updateFilling( const QRectF& rect,
return; return;
} }
const auto fillGradient = gradient.effectiveGradient(); const auto fillGradient = QskBoxRenderer::effectiveGradient( gradient );
const auto shape = shapeMetrics.toAbsolute( rect.size() ); const auto shape = shapeMetrics.toAbsolute( rect.size() );
const bool coloredGeometry = hasHint( PreferColoredGeometry ) const bool coloredGeometry = hasHint( PreferColoredGeometry )
@ -211,13 +211,13 @@ void QskBoxRectangleNode::updateBox( const QRectF& rect,
if ( isDirty ) if ( isDirty )
{ {
/* /*
For monochrome border/fiiling with the same color we might be For monochrome border/filling with the same color we might be
able to do QskFillNode::Monochrome. However this is not implemeted in able to do QskFillNode::Monochrome. However this is not implemeted in
QskBoxRenderer yet. TODO ... QskBoxRenderer yet. TODO ...
*/ */
setColoring( QskFillNode::Polychrome ); setColoring( QskFillNode::Polychrome );
auto fillGradient = gradient.effectiveGradient(); auto fillGradient = QskBoxRenderer::effectiveGradient( gradient );
if ( !QskBoxRenderer::isGradientSupported( fillGradient ) ) if ( !QskBoxRenderer::isGradientSupported( fillGradient ) )
{ {
qWarning() << "QskBoxRenderer does not support radial/conic gradients"; qWarning() << "QskBoxRenderer does not support radial/conic gradients";

View File

@ -231,3 +231,18 @@ void QskBoxRenderer::setColoredBorderAndFillLines( const QRectF& rect,
} }
} }
} }
QskGradient QskBoxRenderer::effectiveGradient( const QskGradient& gradient )
{
if ( ( gradient.type() == QskGradient::Stops ) || gradient.isMonochrome() )
{
// the shader for linear gradients is the fastest
auto g = gradient;
g.setDirection( QskGradient::Linear );
return g;
}
return gradient;
}

View File

@ -54,6 +54,8 @@ namespace QskBoxRenderer
QSK_EXPORT void setColoredBorderAndFillLines( const QRectF&, QSK_EXPORT void setColoredBorderAndFillLines( const QRectF&,
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, const QskBoxShapeMetrics&, const QskBoxBorderMetrics&,
const QskBoxBorderColors&, const QskGradient&, QSGGeometry& ); const QskBoxBorderColors&, const QskGradient&, QSGGeometry& );
QSK_EXPORT QskGradient effectiveGradient( const QskGradient& );
} }
#endif #endif

View File

@ -136,10 +136,12 @@ void QskFillNode::setColoring( const QColor& color )
{ {
setColoring( Monochrome ); setColoring( Monochrome );
const auto colorRgb = color.toRgb();
auto mat = static_cast< QSGFlatColorMaterial* >( material() ); auto mat = static_cast< QSGFlatColorMaterial* >( material() );
if ( mat->color() != color ) if ( mat->color() != colorRgb )
{ {
mat->setColor( color ); mat->setColor( colorRgb );
markDirty( QSGNode::DirtyMaterial ); markDirty( QSGNode::DirtyMaterial );
} }
} }
@ -148,18 +150,27 @@ void QskFillNode::setColoring( const QRectF& rect, const QskGradient& gradient )
{ {
if ( gradient.isMonochrome() ) if ( gradient.isMonochrome() )
{ {
setColoring( gradient.startColor().toRgb() ); setColoring( gradient.startColor() );
} }
else else
{ {
const auto effectiveGradient = gradient.effectiveGradient(); if ( gradient.type() == QskGradient::Stops )
setColoring( qskColoring( effectiveGradient.type() ) ); {
qWarning() << "QskFillNode::setColoring:"
<< "QskGradient::Stops is not supported, using the first color instead.";
setColoring( gradient.startColor() );
}
else
{
setColoring( qskColoring( gradient.type() ) );
auto mat = static_cast< QskGradientMaterial* >( material() ); auto mat = static_cast< QskGradientMaterial* >( material() );
if ( mat->updateGradient( rect, effectiveGradient ) ) if ( mat->updateGradient( rect, gradient ) )
markDirty( QSGNode::DirtyMaterial ); markDirty( QSGNode::DirtyMaterial );
} }
} }
}
void QskFillNode::setHint( Hint hint, bool on ) void QskFillNode::setHint( Hint hint, bool on )
{ {

View File

@ -6,6 +6,7 @@
#include "QskShapeNode.h" #include "QskShapeNode.h"
#include "QskGradient.h" #include "QskGradient.h"
#include "QskGradientDirection.h" #include "QskGradientDirection.h"
#include "QskVertex.h"
#include "QskFillNodePrivate.h" #include "QskFillNodePrivate.h"
QSK_QT_PRIVATE_BEGIN QSK_QT_PRIVATE_BEGIN
@ -13,27 +14,40 @@ QSK_QT_PRIVATE_BEGIN
#include <private/qtriangulator_p.h> #include <private/qtriangulator_p.h>
QSK_QT_PRIVATE_END QSK_QT_PRIVATE_END
#if 0
// keeping the index list
static void qskUpdateGeometry( const QPainterPath& path, static void qskUpdateGeometry( const QPainterPath& path,
const QTransform& transform, QSGGeometry& geometry ) const QTransform& transform, QSGGeometry& geometry )
{ {
const auto ts = qTriangulate( path, transform, 1, false ); const auto ts = qTriangulate( path, transform, 1, false );
#if 1
geometry.allocate( ts.vertices.size(), ts.indices.size() ); geometry.allocate( ts.vertices.size(), ts.indices.size() );
auto vertexData = reinterpret_cast< float* >( geometry.vertexData() ); auto vertexData = reinterpret_cast< float* >( geometry.vertexData() );
const auto points = ts.vertices.constData(); const auto points = ts.vertices.constData();
for ( int i = 0; i < ts.vertices.count(); i++ ) for ( int i = 0; i < ts.vertices.size(); i++ )
vertexData[i] = points[i]; vertexData[i] = points[i];
memcpy( geometry.indexData(), ts.indices.data(), memcpy( geometry.indexData(), ts.indices.data(),
ts.indices.size() * sizeof( quint16 ) ); ts.indices.size() * sizeof( quint16 ) );
#else }
#endif
static void qskUpdateGeometry( const QPainterPath& path,
const QTransform& transform, const QColor& color, QSGGeometry& geometry )
{
const auto ts = qTriangulate( path, transform, 1, false );
/* /*
The triangulation of a random path usually does not lead to index lists
that allow substantially reducing the number of vertices.
As we have to iterate over the vertex buffer to copy qreal to float As we have to iterate over the vertex buffer to copy qreal to float
anyway we could reorder according to the index buffer and drop anyway we reorder according to the index buffer and drop
the index buffer then ??? the index buffer.
QTriangleSet: QTriangleSet:
@ -41,18 +55,32 @@ static void qskUpdateGeometry( const QPainterPath& path,
QVector<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...] QVector<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
QVector<quint16> indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...] QVector<quint16> indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...]
*/ */
const auto points = ts.vertices.constData(); const auto points = ts.vertices.constData();
const auto indices = reinterpret_cast< const quint16* >( ts.indices.data() ); const auto indices = reinterpret_cast< const quint16* >( ts.indices.data() );
geometry.allocate( ts.indices.size() ); geometry.allocate( ts.indices.size() );
if ( color.isValid() )
{
const QskVertex::Color c = color;
auto vertexData = geometry.vertexDataAsColoredPoint2D();
for ( int i = 0; i < ts.indices.size(); i++ )
{
const int j = 2 * indices[i];
vertexData[i].set( points[j], points[j + 1], c.r, c.g, c.b, c.a );
}
}
else
{
auto vertexData = geometry.vertexDataAsPoint2D(); auto vertexData = geometry.vertexDataAsPoint2D();
for ( int i = 0; i < ts.indices.size(); i++ ) for ( int i = 0; i < ts.indices.size(); i++ )
{ {
const int j = 2 * indices[i]; const int j = 2 * indices[i];
vertexData[i].set( points[j], points[j + 1] ); vertexData[i].set( points[j], points[j + 1] );
} }
#endif }
} }
class QskShapeNodePrivate final : public QskFillNodePrivate class QskShapeNodePrivate final : public QskFillNodePrivate
@ -69,7 +97,6 @@ class QskShapeNodePrivate final : public QskFillNodePrivate
QskShapeNode::QskShapeNode() QskShapeNode::QskShapeNode()
: QskFillNode( *new QskShapeNodePrivate ) : QskFillNode( *new QskShapeNodePrivate )
{ {
setColoring( Monochrome );
geometry()->setDrawingMode( QSGGeometry::DrawTriangles ); geometry()->setDrawingMode( QSGGeometry::DrawTriangles );
} }
@ -91,14 +118,24 @@ void QskShapeNode::updateNode( const QPainterPath& path,
return; return;
} }
QColor c;
if ( gradient.isMonochrome() && hasHint( PreferColoredGeometry ) )
c = gradient.startColor();
const bool isDirty = ( isGeometryColored() != c.isValid() );
if ( c.isValid() )
setColoring( QskFillNode::Polychrome );
else
setColoring( rect, gradient ); setColoring( rect, gradient );
if ( ( transform != d->transform ) || ( path != d->path ) ) if ( isDirty || ( transform != d->transform ) || ( path != d->path ) )
{ {
d->path = path; d->path = path;
d->transform = transform; d->transform = transform;
qskUpdateGeometry( path, transform, *geometry() ); qskUpdateGeometry( path, transform, c, *geometry() );
geometry()->markVertexDataDirty(); geometry()->markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry ); markDirty( QSGNode::DirtyGeometry );