qskinny/playground/shadows/BoxShadowNode.cpp

262 lines
6.6 KiB
C++
Raw Normal View History

2021-08-04 10:11:12 +02:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
2020-10-06 15:49:46 +02:00
#include "BoxShadowNode.h"
#include "QskBoxShapeMetrics.h"
#include <QColor>
#include <QSGMaterialShader>
#include <QSGMaterial>
#include <private/qsgnode_p.h>
namespace
{
class Shader final : public QSGMaterialShader
{
2020-12-05 15:09:31 +01:00
public:
2020-10-06 15:49:46 +02:00
Shader();
2020-12-05 15:09:31 +01:00
char const* const* attributeNames() const override;
2020-10-06 15:49:46 +02:00
void initialize() override;
2020-12-05 15:09:31 +01:00
void updateState( const QSGMaterialShader::RenderState& state,
QSGMaterial* newMaterial, QSGMaterial* oldMaterial) override;
2020-10-06 15:49:46 +02:00
private:
2021-09-18 14:48:25 +02:00
int m_matrixId = -1;
int m_opacityId = -1;
int m_aspectId = -1;
int m_blurExtentId = -1;
int m_radiusId = -1;
int m_colorId = -1;
2020-10-06 15:49:46 +02:00
};
class Material final : public QSGMaterial
2020-12-05 15:09:31 +01:00
{
2020-10-06 15:49:46 +02:00
public:
Material();
2020-12-05 15:09:31 +01:00
2020-10-06 15:49:46 +02:00
QSGMaterialShader* createShader() const override;
QSGMaterialType* type() const override;
int compare( const QSGMaterial* other ) const override;
2022-03-23 11:54:34 +01:00
QVector2D aspect = QVector2D{ 1.0, 1.0 };
2021-09-18 14:48:25 +02:00
float blurExtent = 0.0;
2022-03-23 11:54:34 +01:00
QVector4D radius = QVector4D{ 0.0, 0.0, 0.0, 0.0 };
2020-10-06 15:49:46 +02:00
QColor color = Qt::black;
2020-12-05 15:09:31 +01:00
};
2020-10-06 15:49:46 +02:00
Shader::Shader()
{
const QString root( ":/qskinny/shaders/" );
setShaderSourceFile( QOpenGLShader::Vertex, root + "boxshadow.vert" );
setShaderSourceFile( QOpenGLShader::Fragment, root + "boxshadow.frag" );
2020-12-05 15:09:31 +01:00
}
2020-10-06 15:49:46 +02:00
char const* const* Shader::attributeNames() const
{
2020-12-05 15:09:31 +01:00
static char const* const names[] = { "in_vertex", "in_coord", nullptr };
2020-10-06 15:49:46 +02:00
return names;
}
2020-12-05 15:09:31 +01:00
2020-10-06 15:49:46 +02:00
void Shader::initialize()
{
QSGMaterialShader::initialize();
auto p = program();
2021-09-18 14:48:25 +02:00
m_matrixId = p->uniformLocation( "matrix" );
m_aspectId = p->uniformLocation( "aspect" );
m_opacityId = p->uniformLocation( "opacity" );
m_blurExtentId = p->uniformLocation( "blurExtent" );
m_radiusId = p->uniformLocation( "radius" );
m_colorId = p->uniformLocation( "color" );
2020-10-06 15:49:46 +02:00
}
2020-12-05 15:09:31 +01:00
void Shader::updateState( const QSGMaterialShader::RenderState& state,
QSGMaterial* newMaterial, QSGMaterial* oldMaterial )
2020-10-06 15:49:46 +02:00
{
auto p = program();
2020-12-05 15:09:31 +01:00
if ( state.isMatrixDirty() )
2021-09-18 14:48:25 +02:00
p->setUniformValue( m_matrixId, state.combinedMatrix() );
2020-10-06 15:49:46 +02:00
if ( state.isOpacityDirty() )
2021-09-18 14:48:25 +02:00
p->setUniformValue( m_opacityId, state.opacity() );
2020-10-06 15:49:46 +02:00
2021-10-26 10:59:26 +02:00
bool updateMaterial = ( oldMaterial == nullptr )
|| newMaterial->compare( oldMaterial ) != 0;
updateMaterial |= state.isCachedMaterialDataDirty();
if ( updateMaterial )
2020-10-06 15:49:46 +02:00
{
2020-12-05 15:09:31 +01:00
auto material = static_cast< const Material* >( newMaterial );
2020-10-06 15:49:46 +02:00
2021-09-18 14:48:25 +02:00
p->setUniformValue( m_aspectId, material->aspect );
p->setUniformValue( m_blurExtentId, material->blurExtent);
p->setUniformValue( m_radiusId, material->radius );
p->setUniformValue( m_colorId, material->color );
2020-10-06 15:49:46 +02:00
}
}
Material::Material()
{
setFlag( QSGMaterial::Blending, true );
}
2020-12-05 15:09:31 +01:00
2020-10-06 15:49:46 +02:00
QSGMaterialShader* Material::createShader() const
{
return new Shader();
}
QSGMaterialType* Material::type() const
{
static QSGMaterialType staticType;
return &staticType;
}
int Material::compare( const QSGMaterial* other ) const
{
auto material = static_cast< const Material* >( other );
if ( material->color == color
&& material->aspect == aspect
2021-09-18 14:48:25 +02:00
&& qFuzzyCompare(material->blurExtent, blurExtent)
2020-10-06 15:49:46 +02:00
&& qFuzzyCompare(material->radius, radius) )
{
return 0;
}
return QSGMaterial::compare(other);
}
}
class BoxShadowNodePrivate final : public QSGGeometryNodePrivate
{
public:
BoxShadowNodePrivate()
: geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 )
{
}
QSGGeometry geometry;
Material material;
QRectF rect;
};
BoxShadowNode::BoxShadowNode()
: QSGGeometryNode( *new BoxShadowNodePrivate )
{
Q_D( BoxShadowNode );
setGeometry( &d->geometry );
setMaterial( &d->material );
}
BoxShadowNode::~BoxShadowNode()
{
}
void BoxShadowNode::setRect( const QRectF& rect )
{
Q_D( BoxShadowNode );
2020-12-05 15:09:31 +01:00
if ( rect == d->rect )
2020-10-06 15:49:46 +02:00
return;
d->rect = rect;
2021-09-18 14:48:25 +02:00
QVector2D aspect( 1.0, 1.0 );
2020-10-06 15:49:46 +02:00
if ( rect.width() >= rect.height() )
2021-09-18 14:48:25 +02:00
aspect.setX( rect.width() / rect.height() );
2020-10-06 15:49:46 +02:00
else
2021-09-18 14:48:25 +02:00
aspect.setY( rect.height() / rect.width() );
2020-10-06 15:49:46 +02:00
2021-09-18 14:48:25 +02:00
if ( d->material.aspect != aspect )
2020-10-06 15:49:46 +02:00
{
2021-09-18 14:48:25 +02:00
d->material.aspect = aspect;
2020-10-06 15:49:46 +02:00
markDirty( QSGNode::DirtyMaterial );
}
}
void BoxShadowNode::setShape( const QskBoxShapeMetrics& shape )
{
Q_D( BoxShadowNode );
2021-09-18 14:48:25 +02:00
const float t = std::min( d->rect.width(), d->rect.height() );
2020-10-06 15:49:46 +02:00
const float r1 = shape.radius( Qt::BottomRightCorner ).width();
const float r2 = shape.radius( Qt::TopRightCorner ).width();
const float r3 = shape.radius( Qt::BottomLeftCorner ).width();
const float r4 = shape.radius( Qt::TopLeftCorner ).width();
const auto uniformRadius = QVector4D(
std::min( r1 / t, 1.0f ), std::min( r2 / t, 1.0f ),
std::min( r3 / t, 1.0f ), std::min( r4 / t, 1.0f ) );
if ( d->material.radius != uniformRadius )
{
d->material.radius = uniformRadius;
markDirty( QSGNode::DirtyMaterial );
}
}
void BoxShadowNode::setColor( const QColor& color )
{
Q_D( BoxShadowNode );
const auto a = color.alphaF();
const auto c = QColor::fromRgbF(
color.redF() * a, color.greenF() * a, color.blueF() * a, a );
2020-12-05 15:09:31 +01:00
if ( d->material.color != c )
2020-10-06 15:49:46 +02:00
{
d->material.color = c;
2021-09-18 14:48:25 +02:00
markDirty( QSGNode::DirtyMaterial );
2020-10-06 15:49:46 +02:00
}
}
2021-09-18 14:48:25 +02:00
void BoxShadowNode::setBlurRadius( qreal blurRadius )
2020-10-06 15:49:46 +02:00
{
Q_D( BoxShadowNode );
2021-09-18 14:48:25 +02:00
if ( blurRadius <= 0.0 )
blurRadius = 0.0;
2020-10-06 15:49:46 +02:00
2021-09-18 14:48:25 +02:00
const float t = 0.5 * std::min( d->rect.width(), d->rect.height() );
const float uniformExtent = blurRadius / t;
2020-10-06 15:49:46 +02:00
2021-09-18 14:48:25 +02:00
if ( !qFuzzyCompare( d->material.blurExtent, uniformExtent ) )
2020-10-06 15:49:46 +02:00
{
2021-09-18 14:48:25 +02:00
d->material.blurExtent = uniformExtent;
2020-10-06 15:49:46 +02:00
markDirty( QSGNode::DirtyMaterial );
}
}
2021-09-18 14:48:25 +02:00
void BoxShadowNode::setClipRect( const QRectF& rect )
{
Q_UNUSED( rect )
}
2020-10-06 15:49:46 +02:00
void BoxShadowNode::updateGeometry()
{
Q_D( BoxShadowNode );
QSGGeometry::updateTexturedRectGeometry(
2021-09-18 14:48:25 +02:00
&d->geometry, d->rect, QRectF( -0.5, -0.5, 1.0, 1.0 ) );
2020-10-06 15:49:46 +02:00
markDirty( QSGNode::DirtyGeometry );
}