diff --git a/src/nodes/QskBoxFillNode.cpp b/src/nodes/QskBoxFillNode.cpp index ec90f6d1..6650193a 100644 --- a/src/nodes/QskBoxFillNode.cpp +++ b/src/nodes/QskBoxFillNode.cpp @@ -15,8 +15,6 @@ QSK_QT_PRIVATE_BEGIN #include -#include -#include QSK_QT_PRIVATE_END static inline QskHashValue qskMetricsHash( @@ -43,35 +41,6 @@ static inline QskGradient qskEffectiveGradient( const QskGradient& gradient ) return gradient; } -static void qskUpdateGeometry( const QVector< qreal > path, QSGGeometry& geometry ) -{ - const auto hints = QVectorPath::PolygonHint | QVectorPath::OddEvenFill; - const auto ts = qTriangulate( - path.constData(), path.size() / 2, hints, QTransform(), false ); - - /* - As we have to iterate over the vertex buffer to copy qreal to float - anyway we reorder and drop the index buffer. - - QTriangleSet: - - vertices: (x[i[n]], y[i[n]]), (x[j[n]], y[j[n]]), (x[k[n]], y[k[n]]), n = 0, 1, ... - QVector vertices; // [x[0], y[0], x[1], y[1], x[2], ...] - QVector indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...] - */ - const auto points = ts.vertices.constData(); - const auto indices = reinterpret_cast< const quint16* >( ts.indices.data() ); - - geometry.allocate( ts.indices.size() ); - - auto vertexData = geometry.vertexDataAsPoint2D(); - for ( int i = 0; i < ts.indices.size(); i++ ) - { - const int j = 2 * indices[i]; - vertexData[i].set( points[j], points[j + 1] ); - } -} - static inline void qskResetGeometry( QskBoxFillNode* node ) { auto g = node->geometry(); @@ -88,7 +57,6 @@ class QskBoxFillNodePrivate final : public QSGGeometryNodePrivate QskBoxFillNodePrivate() : geometry( QSGGeometry::defaultAttributes_Point2D(), 0 ) { - geometry.setDrawingMode( QSGGeometry::DrawTriangles ); } QskHashValue metricsHash = 0; @@ -138,17 +106,7 @@ void QskBoxFillNode::updateNode( if ( dirtyGeometry ) { - const auto path = QskBoxRenderer().fillPath( - rect, shapeMetrics, borderMetrics ); - - if ( path.isEmpty() ) - { - qskResetGeometry( this ); - return; - } - - qskUpdateGeometry( path, d->geometry ); - + QskBoxRenderer().renderFill( rect, shapeMetrics, borderMetrics, d->geometry ); markDirty( QSGNode::DirtyGeometry ); } diff --git a/src/nodes/QskBoxRenderer.h b/src/nodes/QskBoxRenderer.h index ec40d964..d7668b78 100644 --- a/src/nodes/QskBoxRenderer.h +++ b/src/nodes/QskBoxRenderer.h @@ -7,9 +7,7 @@ #define QSK_BOX_RENDERER_H #include "QskBoxShapeMetrics.h" - #include -#include class QskBoxBorderMetrics; class QskBoxBorderColors; @@ -35,9 +33,6 @@ class QSK_EXPORT QskBoxRenderer const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, const QskBoxBorderColors&, const QskGradient&, QSGGeometry& ); - QVector< qreal > fillPath( const QRectF&, - const QskBoxShapeMetrics&, const QskBoxBorderMetrics& ) const; - class Quad { public: @@ -134,11 +129,6 @@ class QSK_EXPORT QskBoxRenderer int lineCount, QskVertex::ColoredLine* ); void renderRectFill( const Quad&, const QskGradient&, QskVertex::ColoredLine* ); - - QVector< qreal > fillPathRect( const QRectF&, const QskBoxBorderMetrics& ) const; - - QVector< qreal > fillPathRectellipse( const QRectF&, - const QskBoxShapeMetrics&, const QskBoxBorderMetrics& ) const; }; inline void QskBoxRenderer::renderBorder( @@ -172,13 +162,4 @@ inline void QskBoxRenderer::renderBox( const QRectF& rect, renderRectellipse( rect, shape, border, borderColors, gradient, geometry ); } -inline QVector< qreal > QskBoxRenderer::fillPath( const QRectF& rect, - const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border ) const -{ - if ( shape.isRectangle() ) - return fillPathRect( rect, border ); - else - return fillPathRectellipse( rect, shape, border ); -} - #endif diff --git a/src/nodes/QskBoxRendererEllipse.cpp b/src/nodes/QskBoxRendererEllipse.cpp index 71222c3a..df450d11 100644 --- a/src/nodes/QskBoxRendererEllipse.cpp +++ b/src/nodes/QskBoxRendererEllipse.cpp @@ -1301,7 +1301,7 @@ void QskBoxRenderer::renderRectellipseFill( if ( ( metrics.innerQuad.width <= 0 ) || ( metrics.innerQuad.height <= 0 ) ) { - allocateLines< Line >( geometry, 0 ); + geometry.allocate( 0 ); return; } @@ -1309,31 +1309,119 @@ void QskBoxRenderer::renderRectellipseFill( { // degenerated to a rectangle - const QRectF r( metrics.innerQuad.left, metrics.innerQuad.top, - metrics.innerQuad.width, metrics.innerQuad.height ); + geometry.allocate( 4 ); - renderRectFill( r, QskBoxBorderMetrics(), geometry ); + const auto& quad = metrics.innerQuad; + + auto p = geometry.vertexDataAsPoint2D(); + p[0].set( quad.left, quad.top ); + p[1].set( quad.right, quad.top ); + p[2].set( quad.left, quad.bottom ); + p[3].set( quad.right, quad.bottom ); return; } - const int stepCount = metrics.corner[ 0 ].stepCount; + /* + Unfortunately QSGGeometry::DrawTriangleFan is no longer supported with + Qt6 and we have to go with DrawTriangleStrip, duplicating the center with + each each vertex. + */ - int lineCount = 2 * stepCount; + const auto numPoints = + metrics.corner[0].stepCount + metrics.corner[1].stepCount + + metrics.corner[2].stepCount + metrics.corner[3].stepCount + 4; + + /* + points: center point + interpolated corner points + indexes: lines between the center and each point, where + the first line needs to be appended to close the filling + */ + + geometry.allocate( 1 + numPoints, 2 * ( numPoints + 1 ) ); + + Q_ASSERT( geometry.sizeOfIndex() == 2 ); + + auto p = geometry.vertexDataAsPoint2D(); + auto idx = geometry.indexDataAsUShort(); + + int i = 0; + + p[i++].set( rect.x() + 0.5 * rect.width(), rect.y() + 0.5 * rect.height() ); + + BorderValues v( metrics ); - if ( metrics.centerQuad.top >= metrics.centerQuad.bottom ) { - // we need an extra line connecting the top/bottom corners - lineCount++; + constexpr auto id = TopLeft; + const auto& c = metrics.corner[ id ]; + + for ( ArcIterator it( c.stepCount, false ); !it.isDone(); ++it ) + { + *idx++ = 0; + *idx++ = i; + + v.setAngle( it.cos(), it.sin() ); + p[i++].set( c.centerX - v.dx1( id ), c.centerY - v.dy1( id ) ); + } } - else { - // for some reason we have 2 more lines for true ellipses ?? - lineCount += 2; + constexpr auto id = BottomLeft; + const auto& c = metrics.corner[ id ]; + + for ( ArcIterator it( c.stepCount, true ); !it.isDone(); ++it ) + { + *idx++ = 0; + *idx++ = i; + + v.setAngle( it.cos(), it.sin() ); + p[i++].set( c.centerX - v.dx1( id ), c.centerY + v.dy1( id ) ); + } + } + { + constexpr auto id = BottomRight; + const auto& c = metrics.corner[ id ]; + + for ( ArcIterator it( c.stepCount, false ); !it.isDone(); ++it ) + { + *idx++ = 0; + *idx++ = i; + + v.setAngle( it.cos(), it.sin() ); + p[i++].set( c.centerX + v.dx1( id ), c.centerY + v.dy1( id ) ); + } + } + { + constexpr auto id = TopRight; + const auto& c = metrics.corner[ id ]; + + for ( ArcIterator it( c.stepCount, true ); !it.isDone(); ++it ) + { + *idx++ = 0; + *idx++ = i; + + v.setAngle( it.cos(), it.sin() ); + p[i++].set( c.centerX + v.dx1( id ), c.centerY - v.dy1( id ) ); + } } - const auto line = allocateLines< Line >( geometry, lineCount ); - qskRenderFillLines( metrics, Qt::Vertical, line, ColorMapNone() ); + *idx++ = 0; + *idx++ = 1; + +#if 0 + { + auto p = geometry.vertexDataAsPoint2D(); + + qDebug() << "Vertexes:" << geometry.vertexCount(); + for ( int i = 0; i < geometry.vertexCount(); i++ ) + qDebug() << "\t" << i << p[i].x << p[i].y; + + auto idx = geometry.indexDataAsUShort(); + + qDebug() << "Indexes:" << geometry.indexCount(); + for ( int i = 0; i < geometry.indexCount(); i++ ) + qDebug() << "\t" << i << idx[i]; + } +#endif } void QskBoxRenderer::renderRectellipse( const QRectF& rect, @@ -1509,71 +1597,3 @@ void QskBoxRenderer::renderRectellipse( const QRectF& rect, qskRenderBorder( metrics, Qt::Vertical, borderColors, line ); } } - -QVector< qreal > QskBoxRenderer::fillPathRectellipse( const QRectF& rect, - const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border ) const -{ - const Metrics metrics( rect, shape, border ); - BorderValues v( metrics ); - - const auto totalSteps = metrics.corner[0].stepCount - + metrics.corner[1].stepCount - + metrics.corner[2].stepCount - + metrics.corner[3].stepCount; - - QVector< qreal > path; - path.resize( 2 * ( totalSteps + 4 ) ); - - auto p = path.data(); - - { - constexpr auto id = TopLeft; - const auto& c = metrics.corner[ id ]; - - for ( ArcIterator it( c.stepCount, false ); !it.isDone(); ++it ) - { - v.setAngle( it.cos(), it.sin() ); - - *p++ = c.centerX - v.dx1( id ); - *p++ =c.centerY - v.dy1( id ); - } - } - { - constexpr auto id = BottomLeft; - const auto& c = metrics.corner[ id ]; - - for ( ArcIterator it( c.stepCount, true ); !it.isDone(); ++it ) - { - v.setAngle( it.cos(), it.sin() ); - - *p++ = c.centerX - v.dx1( id ); - *p++ = c.centerY + v.dy1( id ); - } - } - { - constexpr auto id = BottomRight; - const auto& c = metrics.corner[ id ]; - - for ( ArcIterator it( c.stepCount, false ); !it.isDone(); ++it ) - { - v.setAngle( it.cos(), it.sin() ); - - *p++ = c.centerX + v.dx1( id ); - *p++ = c.centerY + v.dy1( id ); - } - } - { - constexpr auto id = TopRight; - const auto& c = metrics.corner[ id ]; - - for ( ArcIterator it( c.stepCount, true ); !it.isDone(); ++it ) - { - v.setAngle( it.cos(), it.sin() ); - - *p++ = c.centerX + v.dx1( id ); - *p++ = c.centerY - v.dy1( id ); - } - } - - return path; -} diff --git a/src/nodes/QskBoxRendererRect.cpp b/src/nodes/QskBoxRendererRect.cpp index d7c02794..997ae8d8 100644 --- a/src/nodes/QskBoxRendererRect.cpp +++ b/src/nodes/QskBoxRendererRect.cpp @@ -535,16 +535,22 @@ void QskBoxRenderer::renderRectBorder( const QRectF& rect, void QskBoxRenderer::renderRectFill( const QRectF& rect, const QskBoxBorderMetrics& border, QSGGeometry& geometry ) { - const Quad in = qskValidOrEmptyInnerRect( rect, border.widths() ); + const Quad quad = qskValidOrEmptyInnerRect( rect, border.widths() ); - if ( in.isEmpty() ) + if ( quad.isEmpty() ) { - allocateLines< Line >( geometry, 0 ); + geometry.allocate( 0 ); return; } - const auto line = allocateLines< Line >( geometry, 2 ); - qskCreateFillRandom( Qt::Vertical, in, ColorMapSolid(), line ); + geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip ); + geometry.allocate( 4 ); + + auto p = geometry.vertexDataAsPoint2D(); + p[0].set( quad.left, quad.top ); + p[1].set( quad.right, quad.top ); + p[2].set( quad.left, quad.bottom ); + p[3].set( quad.right, quad.bottom ); } void QskBoxRenderer::renderRect( const QRectF& rect, @@ -664,18 +670,3 @@ void QskBoxRenderer::renderRectFill( const QskBoxRenderer::Quad& rect, { qskCreateFillOrdered( rect, gradient, line ); } - -QVector< qreal > QskBoxRenderer::fillPathRect( const QRectF& rect, - const QskBoxBorderMetrics& border ) const -{ - const auto r = border.adjustedRect( rect ); - if ( r.isEmpty() ) - return QVector< qreal >(); - - const qreal x1 = r.left(); - const qreal x2 = r.right(); - const qreal y1 = r.top(); - const qreal y2 = r.bottom(); - - return { x1, y1, x2, y1, x2, y2, x1, y2, x1, y1 }; -}