2022-09-26 14:44:23 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskShapeNode.h"
|
2022-09-28 20:14:10 +02:00
|
|
|
#include "QskGradientMaterial.h"
|
2022-09-26 14:44:23 +02:00
|
|
|
|
2022-09-28 20:14:10 +02:00
|
|
|
#include <qbrush.h>
|
2022-09-26 14:44:23 +02:00
|
|
|
#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-26 14:44:23 +02:00
|
|
|
{
|
2022-09-29 16:50:46 +02:00
|
|
|
const auto ts = qTriangulate( path, transform, 1, false );
|
2022-09-26 14:44:23 +02:00
|
|
|
|
2022-09-28 20:14:10 +02:00
|
|
|
#if 1
|
2022-09-26 14:44:23 +02:00
|
|
|
geometry.allocate( ts.vertices.size(), ts.indices.size() );
|
|
|
|
|
2022-09-26 17:50:07 +02:00
|
|
|
auto vertexData = reinterpret_cast< float* >( geometry.vertexData() );
|
2022-09-26 14:44:23 +02:00
|
|
|
const auto points = ts.vertices.constData();
|
|
|
|
|
2022-09-28 20:14:10 +02:00
|
|
|
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
|
2022-09-26 14:44:23 +02:00
|
|
|
/*
|
|
|
|
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 ???
|
2022-09-28 20:14:10 +02:00
|
|
|
|
|
|
|
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], ...]
|
2022-09-26 14:44:23 +02:00
|
|
|
*/
|
2022-09-28 20:14:10 +02:00
|
|
|
const auto points = ts.vertices.constData();
|
|
|
|
const auto indices = reinterpret_cast< const quint16* >( ts.indices.data() );
|
2022-09-26 14:44:23 +02:00
|
|
|
|
2022-09-28 20:14:10 +02:00
|
|
|
geometry.allocate( ts.indices.size() );
|
2022-09-26 14:44:23 +02:00
|
|
|
|
2022-09-28 20:14:10 +02:00
|
|
|
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
|
2022-09-26 14:44:23 +02:00
|
|
|
}
|
|
|
|
|
2022-09-29 12:40:22 +02:00
|
|
|
static inline void qskResetGeometry( QskShapeNode* node )
|
|
|
|
{
|
|
|
|
auto g = node->geometry();
|
|
|
|
if ( g->vertexCount() > 0 )
|
|
|
|
{
|
|
|
|
g->allocate( 0 );
|
|
|
|
node->markDirty( QSGNode::DirtyGeometry );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool qskIsGradientVisible( const QGradient* gradient )
|
|
|
|
{
|
|
|
|
if ( gradient && gradient->type() != QGradient::NoGradient )
|
|
|
|
{
|
|
|
|
for ( const auto stop : gradient->stops() )
|
|
|
|
{
|
|
|
|
if ( stop.second.alpha() > 0 )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool qskIsGradientMonochrome( const QGradient* gradient )
|
|
|
|
{
|
|
|
|
if ( gradient && gradient->type() != QGradient::NoGradient )
|
|
|
|
{
|
|
|
|
const auto stops = gradient->stops();
|
|
|
|
|
|
|
|
for ( int i = 1; i < stops.count(); i++ )
|
|
|
|
{
|
|
|
|
if ( stops[i].second != stops[i - 1].second )
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-09-26 14:44:23 +02:00
|
|
|
class QskShapeNodePrivate final : public QSGGeometryNodePrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
QskShapeNodePrivate()
|
|
|
|
: geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
|
|
|
|
{
|
|
|
|
geometry.setDrawingMode( QSGGeometry::DrawTriangles );
|
|
|
|
}
|
|
|
|
|
|
|
|
QSGGeometry geometry;
|
2022-09-29 12:40:22 +02:00
|
|
|
QGradient::Type gradientType = QGradient::NoGradient;
|
2022-09-26 14:44:23 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
QskShapeNode::QskShapeNode()
|
|
|
|
: QSGGeometryNode( *new QskShapeNodePrivate )
|
|
|
|
{
|
|
|
|
Q_D( QskShapeNode );
|
|
|
|
|
|
|
|
setGeometry( &d->geometry );
|
2022-09-30 15:08:19 +02:00
|
|
|
setMaterial( new QSGFlatColorMaterial() );
|
2022-09-26 14:44:23 +02:00
|
|
|
setFlag( QSGNode::OwnsMaterial, true );
|
|
|
|
}
|
|
|
|
|
2022-09-29 16:50:46 +02:00
|
|
|
void QskShapeNode::updateNode( const QPainterPath& path,
|
|
|
|
const QTransform& transform, const QColor& color )
|
2022-09-26 14:44:23 +02:00
|
|
|
{
|
2022-09-29 12:40:22 +02:00
|
|
|
Q_D( QskShapeNode );
|
|
|
|
|
|
|
|
if ( path.isEmpty() || !color.isValid() || color.alpha() == 0 )
|
|
|
|
{
|
|
|
|
qskResetGeometry( this );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-09-26 14:44:23 +02:00
|
|
|
if ( true ) // For the moment we always update the geometry. TODO ...
|
|
|
|
{
|
2022-09-29 16:50:46 +02:00
|
|
|
qskUpdateGeometry( path, transform, d->geometry );
|
2022-09-26 14:44:23 +02:00
|
|
|
markDirty( QSGNode::DirtyGeometry );
|
|
|
|
}
|
|
|
|
|
2022-09-29 12:40:22 +02:00
|
|
|
if ( material() == nullptr || d->gradientType != QGradient::NoGradient )
|
2022-09-26 14:44:23 +02:00
|
|
|
{
|
2022-09-29 12:40:22 +02:00
|
|
|
setMaterial( new QSGFlatColorMaterial() );
|
|
|
|
d->gradientType = QGradient::NoGradient;
|
|
|
|
}
|
2022-09-26 14:44:23 +02:00
|
|
|
|
2022-09-29 12:40:22 +02:00
|
|
|
const auto c = color.toRgb();
|
|
|
|
|
|
|
|
auto colorMaterial = static_cast< QSGFlatColorMaterial* >( material() );
|
|
|
|
if ( colorMaterial->color() != c )
|
|
|
|
{
|
|
|
|
colorMaterial->setColor( c );
|
2022-09-26 14:44:23 +02:00
|
|
|
markDirty( QSGNode::DirtyMaterial );
|
|
|
|
}
|
|
|
|
}
|
2022-09-28 20:14:10 +02:00
|
|
|
|
2022-09-29 16:50:46 +02:00
|
|
|
void QskShapeNode::updateNode( const QPainterPath& path,
|
|
|
|
const QTransform& transform, const QGradient* gradient )
|
2022-09-28 20:14:10 +02:00
|
|
|
{
|
2022-09-29 12:40:22 +02:00
|
|
|
if ( path.isEmpty() || !qskIsGradientVisible( gradient ) )
|
|
|
|
{
|
|
|
|
qskResetGeometry( this );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( qskIsGradientMonochrome( gradient ) )
|
|
|
|
{
|
2022-09-29 16:50:46 +02:00
|
|
|
updateNode( path, transform, gradient->stops().first().first );
|
2022-09-29 12:40:22 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_D( QskShapeNode );
|
|
|
|
|
2022-09-28 20:14:10 +02:00
|
|
|
if ( true ) // For the moment we always update the geometry. TODO ...
|
|
|
|
{
|
2022-09-29 16:50:46 +02:00
|
|
|
qskUpdateGeometry( path, transform, d->geometry );
|
2022-09-28 20:14:10 +02:00
|
|
|
markDirty( QSGNode::DirtyGeometry );
|
|
|
|
}
|
|
|
|
|
2022-09-29 12:40:22 +02:00
|
|
|
if ( ( material() == nullptr ) || gradient->type() != d->gradientType )
|
2022-09-28 20:14:10 +02:00
|
|
|
{
|
2022-09-29 12:40:22 +02:00
|
|
|
setMaterial( QskGradientMaterial::createMaterial( gradient->type() ) );
|
|
|
|
d->gradientType = gradient->type();
|
2022-09-28 20:14:10 +02:00
|
|
|
}
|
2022-09-29 12:40:22 +02:00
|
|
|
|
|
|
|
auto gradientMaterial = static_cast< QskGradientMaterial* >( material() );
|
|
|
|
if ( gradientMaterial->updateGradient( gradient ) )
|
|
|
|
markDirty( QSGNode::DirtyMaterial );
|
2022-09-28 20:14:10 +02:00
|
|
|
}
|
2022-09-29 16:50:46 +02:00
|
|
|
|