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
|
QSK_QT_PRIVATE_BEGIN
|
||||||
#include <private/qsgnode_p.h>
|
#include <private/qsgnode_p.h>
|
||||||
#include <private/qvectorpath_p.h>
|
|
||||||
#include <private/qtriangulator_p.h>
|
|
||||||
QSK_QT_PRIVATE_END
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
static inline QskHashValue qskMetricsHash(
|
static inline QskHashValue qskMetricsHash(
|
||||||
|
@ -43,35 +41,6 @@ static inline QskGradient qskEffectiveGradient( const QskGradient& gradient )
|
||||||
return 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 )
|
static inline void qskResetGeometry( QskBoxFillNode* node )
|
||||||
{
|
{
|
||||||
auto g = node->geometry();
|
auto g = node->geometry();
|
||||||
|
@ -88,7 +57,6 @@ class QskBoxFillNodePrivate final : public QSGGeometryNodePrivate
|
||||||
QskBoxFillNodePrivate()
|
QskBoxFillNodePrivate()
|
||||||
: geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
|
: geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
|
||||||
{
|
{
|
||||||
geometry.setDrawingMode( QSGGeometry::DrawTriangles );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QskHashValue metricsHash = 0;
|
QskHashValue metricsHash = 0;
|
||||||
|
@ -138,17 +106,7 @@ void QskBoxFillNode::updateNode(
|
||||||
|
|
||||||
if ( dirtyGeometry )
|
if ( dirtyGeometry )
|
||||||
{
|
{
|
||||||
const auto path = QskBoxRenderer().fillPath(
|
QskBoxRenderer().renderFill( rect, shapeMetrics, borderMetrics, d->geometry );
|
||||||
rect, shapeMetrics, borderMetrics );
|
|
||||||
|
|
||||||
if ( path.isEmpty() )
|
|
||||||
{
|
|
||||||
qskResetGeometry( this );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qskUpdateGeometry( path, d->geometry );
|
|
||||||
|
|
||||||
markDirty( QSGNode::DirtyGeometry );
|
markDirty( QSGNode::DirtyGeometry );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
#define QSK_BOX_RENDERER_H
|
#define QSK_BOX_RENDERER_H
|
||||||
|
|
||||||
#include "QskBoxShapeMetrics.h"
|
#include "QskBoxShapeMetrics.h"
|
||||||
|
|
||||||
#include <qrect.h>
|
#include <qrect.h>
|
||||||
#include <qvector.h>
|
|
||||||
|
|
||||||
class QskBoxBorderMetrics;
|
class QskBoxBorderMetrics;
|
||||||
class QskBoxBorderColors;
|
class QskBoxBorderColors;
|
||||||
|
@ -35,9 +33,6 @@ class QSK_EXPORT QskBoxRenderer
|
||||||
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&,
|
const QskBoxShapeMetrics&, const QskBoxBorderMetrics&,
|
||||||
const QskBoxBorderColors&, const QskGradient&, QSGGeometry& );
|
const QskBoxBorderColors&, const QskGradient&, QSGGeometry& );
|
||||||
|
|
||||||
QVector< qreal > fillPath( const QRectF&,
|
|
||||||
const QskBoxShapeMetrics&, const QskBoxBorderMetrics& ) const;
|
|
||||||
|
|
||||||
class Quad
|
class Quad
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -134,11 +129,6 @@ class QSK_EXPORT QskBoxRenderer
|
||||||
int lineCount, QskVertex::ColoredLine* );
|
int lineCount, QskVertex::ColoredLine* );
|
||||||
|
|
||||||
void renderRectFill( const Quad&, const QskGradient&, 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(
|
inline void QskBoxRenderer::renderBorder(
|
||||||
|
@ -172,13 +162,4 @@ inline void QskBoxRenderer::renderBox( const QRectF& rect,
|
||||||
renderRectellipse( rect, shape, border, borderColors, gradient, geometry );
|
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
|
#endif
|
||||||
|
|
|
@ -1301,7 +1301,7 @@ void QskBoxRenderer::renderRectellipseFill(
|
||||||
|
|
||||||
if ( ( metrics.innerQuad.width <= 0 ) || ( metrics.innerQuad.height <= 0 ) )
|
if ( ( metrics.innerQuad.width <= 0 ) || ( metrics.innerQuad.height <= 0 ) )
|
||||||
{
|
{
|
||||||
allocateLines< Line >( geometry, 0 );
|
geometry.allocate( 0 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1309,31 +1309,119 @@ void QskBoxRenderer::renderRectellipseFill(
|
||||||
{
|
{
|
||||||
// degenerated to a rectangle
|
// degenerated to a rectangle
|
||||||
|
|
||||||
const QRectF r( metrics.innerQuad.left, metrics.innerQuad.top,
|
geometry.allocate( 4 );
|
||||||
metrics.innerQuad.width, metrics.innerQuad.height );
|
|
||||||
|
|
||||||
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;
|
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
|
constexpr auto id = TopLeft;
|
||||||
lineCount++;
|
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 ??
|
constexpr auto id = BottomLeft;
|
||||||
lineCount += 2;
|
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 );
|
*idx++ = 0;
|
||||||
qskRenderFillLines( metrics, Qt::Vertical, line, ColorMapNone() );
|
*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,
|
void QskBoxRenderer::renderRectellipse( const QRectF& rect,
|
||||||
|
@ -1509,71 +1597,3 @@ void QskBoxRenderer::renderRectellipse( const QRectF& rect,
|
||||||
qskRenderBorder( metrics, Qt::Vertical, borderColors, line );
|
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,
|
void QskBoxRenderer::renderRectFill( const QRectF& rect,
|
||||||
const QskBoxBorderMetrics& border, QSGGeometry& geometry )
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto line = allocateLines< Line >( geometry, 2 );
|
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
|
||||||
qskCreateFillRandom( Qt::Vertical, in, ColorMapSolid(), line );
|
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,
|
void QskBoxRenderer::renderRect( const QRectF& rect,
|
||||||
|
@ -664,18 +670,3 @@ void QskBoxRenderer::renderRectFill( const QskBoxRenderer::Quad& rect,
|
||||||
{
|
{
|
||||||
qskCreateFillOrdered( rect, gradient, line );
|
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…
Reference in New Issue