6#include "QskBoxShadowNode.h"
7#include "QskBoxShapeMetrics.h"
10#include <qsgmaterialshader.h>
11#include <qsgmaterial.h>
14#include <private/qsgnode_p.h>
19#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
20 #include <QSGMaterialRhiShader>
21 using RhiShader = QSGMaterialRhiShader;
23 using RhiShader = QSGMaterialShader;
28 class Material final :
public QSGMaterial
33#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
34 QSGMaterialShader* createShader()
const override;
36 QSGMaterialShader* createShader( QSGRendererInterface::RenderMode )
const override;
39 QSGMaterialType* type()
const override;
41 int compare(
const QSGMaterial* other )
const override;
43 QVector2D m_aspectRatio = QVector2D{ 1, 1 };
44 QVector4D m_radius = QVector4D{ 0, 0, 0, 0 };
45 QVector4D m_color = QVector4D{ 0, 0, 0, 1 };
46 float m_blurExtent = 0.0;
52 class ShaderRhi final :
public RhiShader
57 const QString root(
":/qskinny/shaders/" );
59 setShaderFileName( VertexStage, root +
"boxshadow.vert.qsb" );
60 setShaderFileName( FragmentStage, root +
"boxshadow.frag.qsb" );
63 bool updateUniformData( RenderState& state,
64 QSGMaterial* newMaterial, QSGMaterial* oldMaterial )
override
66 const auto matOld =
static_cast< Material*
>( oldMaterial );
67 const auto matNew =
static_cast< Material*
>( newMaterial );
69 Q_ASSERT( state.uniformData()->size() >= 112 );
71 auto data = state.uniformData()->data();
74 if ( state.isMatrixDirty() )
76 const auto matrix = state.combinedMatrix();
77 memcpy( data + 0, matrix.constData(), 64 );
82 if ( matOld ==
nullptr || matNew->m_color != matOld->m_color )
84 memcpy( data + 64, &matNew->m_color, 16 );
88 if ( matOld ==
nullptr || matNew->m_radius != matOld->m_radius )
90 memcpy( data + 80, &matNew->m_radius, 16 );
94 if ( matOld ==
nullptr || matNew->m_aspectRatio != matOld->m_aspectRatio )
96 memcpy( data + 96, &matNew->m_aspectRatio, 8 );
100 if ( matOld ==
nullptr || matNew->m_blurExtent != matOld->m_blurExtent )
102 memcpy( data + 104, &matNew->m_blurExtent, 4 );
106 if ( state.isOpacityDirty() )
108 const float opacity = state.opacity();
109 memcpy( data + 108, &opacity, 4 );
119#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
125 class ShaderGL final :
public QSGMaterialShader
130 const QString root(
":/qskinny/shaders/" );
132 setShaderSourceFile( QOpenGLShader::Vertex, root +
"boxshadow.vert" );
133 setShaderSourceFile( QOpenGLShader::Fragment, root +
"boxshadow.frag" );
136 char const*
const* attributeNames()
const override
138 static char const*
const names[] = {
"in_vertex",
"in_coord",
nullptr };
142 void initialize()
override
144 QSGMaterialShader::initialize();
148 m_matrixId = p->uniformLocation(
"matrix" );
149 m_aspectRatioId = p->uniformLocation(
"aspectRatio" );
150 m_opacityId = p->uniformLocation(
"opacity" );
151 m_blurExtentId = p->uniformLocation(
"blurExtent" );
152 m_radiusId = p->uniformLocation(
"radius" );
153 m_colorId = p->uniformLocation(
"color" );
156 void updateState(
const QSGMaterialShader::RenderState& state,
157 QSGMaterial* newMaterial, QSGMaterial* oldMaterial)
override
161 if ( state.isMatrixDirty() )
162 p->setUniformValue( m_matrixId, state.combinedMatrix() );
164 if ( state.isOpacityDirty() )
165 p->setUniformValue( m_opacityId, state.opacity() );
167 bool updateMaterial = ( oldMaterial == nullptr )
168 || newMaterial->compare( oldMaterial ) != 0;
170 updateMaterial |= state.isCachedMaterialDataDirty();
172 if ( updateMaterial )
174 auto material =
static_cast< const Material*
>( newMaterial );
176 p->setUniformValue( m_aspectRatioId, material->m_aspectRatio );
177 p->setUniformValue( m_blurExtentId, material->m_blurExtent);
178 p->setUniformValue( m_radiusId, material->m_radius );
179 p->setUniformValue( m_colorId, material->m_color );
185 int m_opacityId = -1;
186 int m_aspectRatioId = -1;
187 int m_blurExtentId = -1;
197 setFlag( QSGMaterial::Blending,
true );
199#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
200 setFlag( QSGMaterial::SupportsRhiShader,
true );
204#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
206QSGMaterialShader* Material::createShader()
const
208 if ( !( flags() & QSGMaterial::RhiShaderWanted ) )
209 return new ShaderGL();
211 return new ShaderRhi();
216QSGMaterialShader* Material::createShader( QSGRendererInterface::RenderMode )
const
218 return new ShaderRhi();
223QSGMaterialType* Material::type()
const
225 static QSGMaterialType staticType;
229int Material::compare(
const QSGMaterial* other )
const
231 auto material =
static_cast< const Material*
>( other );
233 if ( ( material->m_color == m_color )
234 && ( material->m_aspectRatio == m_aspectRatio )
235 && qFuzzyCompare(material->m_blurExtent, m_blurExtent)
236 && qFuzzyCompare(material->m_radius, m_radius) )
241 return QSGMaterial::compare( other );
244class QskBoxShadowNodePrivate final :
public QSGGeometryNodePrivate
247 QskBoxShadowNodePrivate()
248 : geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 )
252 QSGGeometry geometry;
258QskBoxShadowNode::QskBoxShadowNode()
259 : QSGGeometryNode( *new QskBoxShadowNodePrivate )
263 setGeometry( &d->geometry );
264 setMaterial( &d->material );
267QskBoxShadowNode::~QskBoxShadowNode()
271void QskBoxShadowNode::setShadowData(
273 qreal blurRadius,
const QColor& color )
277 if ( rect != d->rect )
281 QSGGeometry::updateTexturedRectGeometry(
282 &d->geometry, d->rect, QRectF( -0.5, -0.5, 1.0, 1.0 ) );
284 d->geometry.markVertexDataDirty();
285 markDirty( QSGNode::DirtyGeometry );
287 QVector2D aspectRatio( 1.0, 1.0 );
289 if ( rect.width() >= rect.height() )
290 aspectRatio.setX( rect.width() / rect.height() );
292 aspectRatio.setY( rect.height() / rect.width() );
294 if ( d->material.m_aspectRatio != aspectRatio )
296 d->material.m_aspectRatio = aspectRatio;
297 markDirty( QSGNode::DirtyMaterial );
302 const auto shape = shapeMetrics.toAbsolute( rect.size() );
304 const float t = std::min( d->rect.width(), d->rect.height() );
306 const float r1 = shape.radius( Qt::BottomRightCorner ).width();
307 const float r2 = shape.radius( Qt::TopRightCorner ).width();
308 const float r3 = shape.radius( Qt::BottomLeftCorner ).width();
309 const float r4 = shape.radius( Qt::TopLeftCorner ).width();
311 const auto uniformRadius = QVector4D(
312 std::min( r1 / t, 1.0f ), std::min( r2 / t, 1.0f ),
313 std::min( r3 / t, 1.0f ), std::min( r4 / t, 1.0f ) );
315 if ( d->material.m_radius != uniformRadius )
317 d->material.m_radius = uniformRadius;
318 markDirty( QSGNode::DirtyMaterial );
323 if ( blurRadius <= 0.0 )
326 const float t = 0.5 * std::min( d->rect.width(), d->rect.height() );
327 const float uniformExtent = blurRadius / t;
329 if ( !qFuzzyCompare( d->material.m_blurExtent, uniformExtent ) )
331 d->material.m_blurExtent = uniformExtent;
332 markDirty( QSGNode::DirtyMaterial );
337 const auto a = color.alphaF();
339 const QVector4D c( color.redF() * a, color.greenF() * a, color.blueF() * a, a );
341 if ( d->material.m_color != c )
343 d->material.m_color = c;
344 markDirty( QSGNode::DirtyMaterial );