calculating vertexes manually instead of using the expensive painter
path triangulator
This commit is contained in:
parent
4888fcc5ba
commit
d82f3d08ff
@ -15,8 +15,6 @@
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qsgnode_p.h>
|
||||
#include <private/qvectorpath_p.h>
|
||||
#include <private/qtriangulator_p.h>
|
||||
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<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], ...]
|
||||
*/
|
||||
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 );
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,7 @@
|
||||
#define QSK_BOX_RENDERER_H
|
||||
|
||||
#include "QskBoxShapeMetrics.h"
|
||||
|
||||
#include <qrect.h>
|
||||
#include <qvector.h>
|
||||
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 };
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user