qskinny/src/nodes/QskFillNode.cpp

195 lines
4.9 KiB
C++

/******************************************************************************
* QSkinny - Copyright (C) The authors
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskFillNode.h"
#include "QskGradientMaterial.h"
#include "QskFillNodePrivate.h"
#include "QskSGNode.h"
#include <qsgflatcolormaterial.h>
#include <qsgvertexcolormaterial.h>
#include <qglobalstatic.h>
Q_GLOBAL_STATIC( QSGVertexColorMaterial, qskMaterialColorVertex )
static inline QskGradient::Type qskGradientType( QskFillNode::Coloring coloring )
{
const auto type = QskGradient::Linear + coloring - QskFillNode::Linear;
return static_cast< QskGradient::Type >( type );
}
static inline QskFillNode::Coloring qskColoring( QskGradient::Type type )
{
const auto coloring = QskFillNode::Linear + type - QskGradient::Linear;
return static_cast< QskFillNode::Coloring >( coloring );
}
static inline QskFillNode::Hints qskDefaultFillNodeHints()
{
extern bool qskHasEnvironment( const char* );
QskFillNode::Hints hints;
if ( !qskHasEnvironment( "QSK_PREFER_SHADER_COLORS" ) )
hints |= QskFillNode::PreferColoredGeometry;
return hints;
}
QskFillNode::QskFillNode()
: QskFillNode( *new QskFillNodePrivate )
{
}
QskFillNode::QskFillNode( QskFillNodePrivate& dd )
: QSGGeometryNode( dd )
{
static const auto hints = qskDefaultFillNodeHints();
dd.hints = hints;
setGeometry( &dd.geometry );
setMaterial( qskMaterialColorVertex );
setFlag( QSGNode::OwnsMaterial, false );
}
QskFillNode::~QskFillNode()
{
}
void QskFillNode::resetGeometry()
{
QskSGNode::resetGeometry( this );
}
void QskFillNode::setColoring( Coloring coloring )
{
Q_D( QskFillNode );
if ( coloring == d->coloring )
return;
d->coloring = coloring;
switch( coloring )
{
case Monochrome:
{
setMaterial( new QSGFlatColorMaterial() );
break;
}
case Polychrome:
{
setMaterial( qskMaterialColorVertex );
break;
}
/*
QSGDefaultInternalRectangleNode is using QSGSmoothColorMaterial.
Can we do something useful with it too ? TODO ...
*/
default:
{
const auto gradientType = qskGradientType( coloring );
setMaterial( QskGradientMaterial::createMaterial( gradientType ) );
}
}
if ( material() == qskMaterialColorVertex )
{
/*
All color information is stored in the geometry and we can share
the material regardless of the specific colors.
As nodes with the same material can be batched it might make sense
to use this type of coloring for monochrome fillings: memory vs. performance.
*/
setFlag( QSGNode::OwnsMaterial, false ); // shared: do not delete
if ( !isGeometryColored() )
{
const QSGGeometry g( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 );
memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) );
}
}
else
{
setFlag( QSGNode::OwnsMaterial, true );
if ( isGeometryColored() )
{
const QSGGeometry g( QSGGeometry::defaultAttributes_Point2D(), 0 );
memcpy( ( void* ) &d->geometry, ( void* ) &g, sizeof( QSGGeometry ) );
}
}
}
QskFillNode::Coloring QskFillNode::coloring() const
{
return static_cast< QskFillNode::Coloring >( d_func()->coloring );
}
void QskFillNode::setColoring( const QColor& color )
{
setColoring( Monochrome );
auto mat = static_cast< QSGFlatColorMaterial* >( material() );
if ( mat->color() != color )
{
mat->setColor( color );
markDirty( QSGNode::DirtyMaterial );
}
}
void QskFillNode::setColoring( const QRectF& rect, const QskGradient& gradient )
{
if ( gradient.isMonochrome() )
{
setColoring( gradient.startColor().toRgb() );
}
else
{
const auto effectiveGradient = gradient.effectiveGradient();
setColoring( qskColoring( effectiveGradient.type() ) );
auto mat = static_cast< QskGradientMaterial* >( material() );
if ( mat->updateGradient( rect, effectiveGradient ) )
markDirty( QSGNode::DirtyMaterial );
}
}
void QskFillNode::setHint( Hint hint, bool on )
{
Q_D( QskFillNode );
if ( on )
d->hints |= hint;
else
d->hints &= ~hint;
}
void QskFillNode::setHints( Hints hints )
{
d_func()->hints = hints;
}
QskFillNode::Hints QskFillNode::hints() const
{
return static_cast< QskFillNode::Hints >( d_func()->hints );
}
bool QskFillNode::hasHint( Hint hint ) const
{
return d_func()->hints & hint;
}
bool QskFillNode::isGeometryColored() const
{
return d_func()->geometry.attributeCount() != 1;
}
#include "moc_QskFillNode.cpp"