qskinny/src/nodes/QskBoxNode.cpp

196 lines
5.0 KiB
C++
Raw Normal View History

2017-07-21 18:21:34 +02:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskBoxNode.h"
#include "QskBoxOptions.h"
#include "QskBoxRenderer.h"
2017-07-21 18:21:34 +02:00
#include <QSGVertexColorMaterial>
#include <QSGFlatColorMaterial>
2017-07-21 18:21:34 +02:00
static QSGVertexColorMaterial qskMaterialVertex;
static inline bool qskHasAlpha( const QRgb* rgbValues )
2017-07-21 18:21:34 +02:00
{
return qAlpha( rgbValues[0] ) || qAlpha( rgbValues[1] )
|| qAlpha( rgbValues[2] ) || qAlpha( rgbValues[3] );
}
static inline bool qskIsMonochrome( const QRgb* rgbValues )
{
return ( rgbValues[0] == rgbValues[1] )
&& ( rgbValues[1] == rgbValues[2] )
&& ( rgbValues[2] == rgbValues[3] );
}
2017-07-21 18:21:34 +02:00
static inline uint qskMetricsHash( const QskBoxOptions& options )
{
uint hash = 13000;
hash = options.shape.hash( hash );
return options.border.hash( hash );
}
2017-07-21 18:21:34 +02:00
static inline uint qskColorsHash( const QskBoxOptions& options )
{
uint hash = 13000;
hash = options.borderColors.hash( hash );
return options.fillGradient.hash( hash );
2017-07-21 18:21:34 +02:00
}
QskBoxNode::QskBoxNode():
m_metricsHash( 0 ),
m_colorsHash( 0 ),
m_geometry( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 )
2017-07-21 18:21:34 +02:00
{
setMaterial( &qskMaterialVertex );
2017-07-21 18:21:34 +02:00
setGeometry( &m_geometry );
}
QskBoxNode::~QskBoxNode()
{
if ( material() != &qskMaterialVertex )
delete material();
2017-07-21 18:21:34 +02:00
}
void QskBoxNode::setBoxData( const QRectF& rect, const QskBoxOptions& options )
{
#if 1
const uint metricsHash = qskMetricsHash( options );
const uint colorsHash = qskColorsHash( options );
2017-07-21 18:21:34 +02:00
if ( ( metricsHash == m_metricsHash ) &&
( colorsHash == m_colorsHash ) && ( rect == m_rect ) )
2017-07-21 18:21:34 +02:00
{
return;
}
m_metricsHash = metricsHash;
m_colorsHash = colorsHash;
m_rect = rect;
markDirty( QSGNode::DirtyMaterial );
markDirty( QSGNode::DirtyGeometry );
2017-07-21 18:21:34 +02:00
#endif
if ( rect.isEmpty() )
{
m_geometry.allocate( 0 );
return;
2017-07-21 18:21:34 +02:00
}
const auto& gradient = options.fillGradient;
const auto& borderMetrics = options.border;
const auto& borderColors = options.borderColors;
bool hasFill = options.fillGradient.isValid();
bool hasBorder = !borderMetrics.isNull();
if ( hasBorder )
2017-07-21 18:21:34 +02:00
{
/*
Wrong as the border width should have an
effect - even if not being visible. TODO ...
*/
2017-07-21 18:21:34 +02:00
hasBorder = borderColors.isVisible();
}
2017-07-21 18:21:34 +02:00
if ( !hasBorder && !hasFill )
{
m_geometry.allocate( 0 );
return;
2017-07-21 18:21:34 +02:00
}
const bool isFillMonochrome = hasFill ? gradient.isMonochrome() : true;
const bool isBorderMonochrome = hasBorder ? borderColors.isMonochrome() : true;
if ( hasFill && hasBorder )
2017-07-21 18:21:34 +02:00
{
if ( isFillMonochrome && isBorderMonochrome )
{
if ( borderColors.color( Qsk::Left ) == gradient.startColor() )
{
// we can draw border and background in one
hasBorder = false;
}
}
}
bool maybeFlat = false;
2017-07-21 18:21:34 +02:00
/*
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.
*/
2017-07-21 18:21:34 +02:00
if ( maybeFlat )
{
if ( ( hasFill && hasBorder ) || ( hasFill && !isFillMonochrome )
|| ( hasBorder && !isBorderMonochrome ) )
{
maybeFlat = false;
}
}
2017-07-21 18:21:34 +02:00
QskBoxRenderer renderer;
2017-07-21 18:21:34 +02:00
if ( !maybeFlat )
{
setMonochrome( false );
2017-07-21 18:21:34 +02:00
renderer.renderBox( m_rect, options.shape, options.border,
options.borderColors, options.fillGradient, *geometry() );
}
else
{
// all is done with one color
setMonochrome( true );
auto* flatMaterial = static_cast< QSGFlatColorMaterial *>( material() );
if ( hasFill )
{
flatMaterial->setColor( gradient.startColor() );
renderer.renderFill( m_rect, options.shape,
QskBoxBorderMetrics(), *geometry() );
}
else
{
flatMaterial->setColor( borderColors.color( Qsk::Left ).rgba() );
renderer.renderBorder( m_rect, options.shape,
options.border, *geometry() );
}
2017-07-21 18:21:34 +02:00
}
}
void QskBoxNode::setMonochrome( bool on )
2017-07-21 18:21:34 +02:00
{
const auto material = this->material();
if ( on == ( material != &qskMaterialVertex ) )
return;
m_geometry.allocate( 0 );
if ( on )
{
setMaterial( new QSGFlatColorMaterial() );
const QSGGeometry g( QSGGeometry::defaultAttributes_Point2D(), 0 );
memcpy( &m_geometry, &g, sizeof( QSGGeometry ) );
}
else
{
setMaterial( &qskMaterialVertex );
delete material;
const QSGGeometry g( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 );
memcpy( &m_geometry, &g, sizeof( QSGGeometry ) );
}
2017-07-21 18:21:34 +02:00
}