qskinny/src/nodes/QskBoxRectangleNode.cpp

195 lines
5.0 KiB
C++
Raw Normal View History

/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
2023-04-06 07:23:37 +00:00
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskBoxRectangleNode.h"
#include "QskBoxBorderColors.h"
#include "QskBoxBorderMetrics.h"
#include "QskBoxRenderer.h"
#include "QskBoxShapeMetrics.h"
#include "QskGradient.h"
#include "QskGradientDirection.h"
2023-11-15 10:47:56 +00:00
#include "QskFillNodePrivate.h"
static inline QskHashValue qskMetricsHash(
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics )
{
QskHashValue hash = 13000;
hash = shape.hash( hash );
return borderMetrics.hash( hash );
}
static inline QskHashValue qskColorsHash(
const QskBoxBorderColors& borderColors, const QskGradient& fillGradient )
{
QskHashValue hash = 13000;
hash = borderColors.hash( hash );
return fillGradient.hash( hash );
}
#if 1
static inline QskGradient qskEffectiveGradient( const QskGradient& gradient )
{
2022-12-22 19:13:45 +00:00
auto g = gradient.effectiveGradient();
if ( g.type() != QskGradient::Linear )
2022-12-22 19:27:17 +00:00
{
qWarning() << "QskBoxRectangleNode does not support radial/conic gradients";
g.setDirection( QskGradient::Linear );
}
return g;
}
#endif
2023-11-15 10:47:56 +00:00
class QskBoxRectangleNodePrivate final : public QskFillNodePrivate
{
public:
QskHashValue metricsHash = 0;
QskHashValue colorsHash = 0;
QRectF rect;
};
QskBoxRectangleNode::QskBoxRectangleNode()
2023-11-15 10:47:56 +00:00
: QskFillNode( *new QskBoxRectangleNodePrivate )
{
}
QskBoxRectangleNode::~QskBoxRectangleNode()
{
}
void QskBoxRectangleNode::updateNode(
const QRectF& rect, const QskGradient& fillGradient )
{
updateNode( rect, QskBoxShapeMetrics(), QskBoxBorderMetrics(),
QskBoxBorderColors(), fillGradient );
}
2022-12-30 09:27:18 +00:00
void QskBoxRectangleNode::updateNode( const QRectF& rect,
const QskBoxShapeMetrics& shape, const QskGradient& fillGradient )
{
updateNode( rect, shape, QskBoxBorderMetrics(),
QskBoxBorderColors(), fillGradient );
}
void QskBoxRectangleNode::updateNode( const QRectF& rect,
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics,
const QskBoxBorderColors& borderColors, const QskGradient& gradient )
{
Q_D( QskBoxRectangleNode );
/*
We supports certain linear gradients only.
Everything else has to be done using QskRectangleNode
*/
const auto fillGradient = qskEffectiveGradient( gradient );
const auto metricsHash = qskMetricsHash( shape, borderMetrics );
const auto colorsHash = qskColorsHash( borderColors, fillGradient );
if ( ( metricsHash == d->metricsHash ) &&
( colorsHash == d->colorsHash ) && ( rect == d->rect ) )
{
return;
}
d->metricsHash = metricsHash;
d->colorsHash = colorsHash;
d->rect = rect;
markDirty( QSGNode::DirtyMaterial );
markDirty( QSGNode::DirtyGeometry );
if ( rect.isEmpty() )
{
2023-11-15 10:47:56 +00:00
resetGeometry();
return;
}
bool hasFill = fillGradient.isVisible();
bool hasBorder = !borderMetrics.isNull();
if ( hasBorder )
{
/*
Wrong as the border width should have an
effect - even if not being visible. TODO ...
*/
hasBorder = borderColors.isVisible();
}
if ( !hasBorder && !hasFill )
{
2023-11-15 10:47:56 +00:00
resetGeometry();
return;
}
const bool isFillMonochrome = hasFill ? fillGradient.isMonochrome() : true;
const bool isBorderMonochrome = hasBorder ? borderColors.isMonochrome() : true;
if ( hasFill && hasBorder )
{
if ( isFillMonochrome && isBorderMonochrome )
{
if ( borderColors.left().rgbStart() == fillGradient.rgbStart() )
{
// we can draw border and background in one
hasBorder = false;
}
}
}
2023-11-15 10:47:56 +00:00
auto coloring = QskFillNode::Polychrome;
#if 0
/*
Always using the same material result in a better batching
but wastes some memory. when we have a solid color.
Maybe its worth to introduce a flag to control the behaviour,
but for the moment we go with performance.
*/
2023-11-15 10:47:56 +00:00
if ( !( hasFill && hasBorder ) )
{
2023-11-15 10:47:56 +00:00
if ( ( hasFill && isFillMonochrome )
|| ( hasBorder && !isBorderMonochrome )
{
2023-11-15 10:47:56 +00:00
coloring = QskFillNode::Monochrome;
}
}
#endif
2023-11-15 10:47:56 +00:00
auto& geometry = *this->geometry();
if ( coloring == QskFillNode::Polychrome )
{
2023-11-15 10:47:56 +00:00
setColoring( coloring );
QskBox::renderBox( d->rect, shape, borderMetrics,
2023-11-15 10:47:56 +00:00
borderColors, fillGradient, geometry );
}
else
{
if ( hasFill )
{
2023-11-15 10:47:56 +00:00
setColoring( fillGradient.rgbStart() );
QskBox::renderFillGeometry(
2023-11-15 10:47:56 +00:00
d->rect, shape, QskBoxBorderMetrics(), geometry );
}
else
{
2023-11-15 10:47:56 +00:00
setColoring( borderColors.left().rgbStart() );
QskBox::renderBorderGeometry(
2023-11-15 10:47:56 +00:00
d->rect, shape, borderMetrics, geometry );
}
}
2023-11-15 10:47:56 +00:00
geometry.markVertexDataDirty();
}