qskinny/src/nodes/QskShapeNode.cpp

156 lines
4.7 KiB
C++
Raw Normal View History

/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
2023-04-06 09:23:37 +02:00
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskShapeNode.h"
#include "QskGradientMaterial.h"
2022-10-31 14:42:08 +01:00
#include "QskGradient.h"
#include "QskGradientDirection.h"
2022-12-05 17:00:54 +01:00
#include "QskSGNode.h"
#include <qsgflatcolormaterial.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
#include <private/qvectorpath_p.h>
#include <private/qtriangulator_p.h>
QSK_QT_PRIVATE_END
2022-09-29 16:50:46 +02:00
static void qskUpdateGeometry( const QPainterPath& path,
const QTransform& transform, QSGGeometry& geometry )
{
2022-09-29 16:50:46 +02:00
const auto ts = qTriangulate( path, transform, 1, false );
#if 1
geometry.allocate( ts.vertices.size(), ts.indices.size() );
2022-09-26 17:50:07 +02:00
auto vertexData = reinterpret_cast< float* >( geometry.vertexData() );
const auto points = ts.vertices.constData();
for ( int i = 0; i < ts.vertices.count(); i++ )
vertexData[i] = points[i];
memcpy( geometry.indexData(), ts.indices.data(),
ts.indices.size() * sizeof( quint16 ) );
#else
/*
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
the index buffer then ???
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] );
}
#endif
}
class QskShapeNodePrivate final : public QSGGeometryNodePrivate
{
public:
QskShapeNodePrivate()
: geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
{
geometry.setDrawingMode( QSGGeometry::DrawTriangles );
}
QSGGeometry geometry;
2022-10-31 14:42:08 +01:00
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 ) ?
*/
QPainterPath path;
QTransform transform;
};
QskShapeNode::QskShapeNode()
: QSGGeometryNode( *new QskShapeNodePrivate )
{
Q_D( QskShapeNode );
setGeometry( &d->geometry );
setMaterial( new QSGFlatColorMaterial() );
setFlag( QSGNode::OwnsMaterial, true );
}
2022-09-29 16:50:46 +02:00
void QskShapeNode::updateNode( const QPainterPath& path,
2022-10-31 14:42:08 +01:00
const QTransform& transform, const QRectF& rect, const QskGradient& gradient )
{
Q_D( QskShapeNode );
2022-10-31 14:42:08 +01:00
if ( path.isEmpty() || !gradient.isVisible() )
2022-09-29 12:40:22 +02:00
{
d->path = QPainterPath();
2022-12-05 13:05:13 +01:00
d->transform = QTransform();
2022-12-05 17:00:54 +01:00
QskSGNode::resetGeometry( this );
2022-09-29 12:40:22 +02:00
return;
}
if ( ( transform != d->transform ) || ( path != d->path ) )
{
d->path = path;
d->transform = transform;
2022-09-29 16:50:46 +02:00
qskUpdateGeometry( path, transform, d->geometry );
markDirty( QSGNode::DirtyGeometry );
}
2022-12-05 13:05:13 +01:00
if ( gradient.isMonochrome() )
{
2022-12-05 13:05:13 +01:00
if ( material() == nullptr || d->gradientType >= 0 )
{
setMaterial( new QSGFlatColorMaterial() );
d->gradientType = -1;
}
const auto color = gradient.startColor().toRgb();
2023-01-24 19:47:37 +01:00
/*
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".
*/
2022-12-05 13:05:13 +01:00
auto mat = static_cast< QSGFlatColorMaterial* >( material() );
if ( mat->color() != color )
{
mat->setColor( color );
markDirty( QSGNode::DirtyMaterial );
}
}
else
{
2022-12-22 20:13:45 +01:00
const auto effectiveGradient = gradient.effectiveGradient();
2022-12-05 13:05:13 +01:00
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 );
}
}