QskBoxShadowNode introduced ( from playground/shadows )

- shader code migrated from glsl to vulkan-glsl
   - #ifdef "Geschnetzel" introduced to support old and rhi graphic APIs
   - iotdashboard, shadows examples adjusted
This commit is contained in:
Uwe Rathmann 2022-06-04 17:56:14 +02:00
parent e5af877246
commit 0ed9afe2b4
21 changed files with 483 additions and 614 deletions

View File

@ -6,15 +6,13 @@
#include "LightDisplaySkinlet.h"
#include "LightDisplay.h"
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
#include "nodes/BoxShadowNode.h"
#endif
#include "nodes/RadialTickmarksNode.h"
#include <QskArcMetrics.h>
#include <QskTextOptions.h>
#include <QskScaleTickmarks.h>
#include <QskBoxShadowNode.h>
#include <QskSGNode.h>
#include <QFontMetrics>
#include <QtMath>
@ -144,9 +142,7 @@ QSGNode* LightDisplaySkinlet::updateSubNode(
if ( grooveRect.isEmpty() )
return nullptr;
auto shadowNode = static_cast< BoxShadowNode* >( node );
if ( shadowNode == nullptr )
shadowNode = new BoxShadowNode();
auto shadowNode = QskSGNode::ensureNode< QskBoxShadowNode >( node );
const auto& shadowMetrics = display->shadow();

View File

@ -5,11 +5,10 @@
#include "ShadowedBox.h"
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
#include "nodes/BoxShadowNode.h"
#endif
#include <QskBoxNode.h>
#include <QskBoxShadowNode.h>
#include <QskSGNode.h>
#include <QskBoxBorderMetrics.h>
#include <QskBoxBorderColors.h>
#include <QskGradient.h>
@ -50,15 +49,12 @@ namespace
switch ( nodeRole )
{
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
case ShadowRole:
{
auto shadowNode = static_cast< BoxShadowNode* >( node );
if ( shadowNode == nullptr )
shadowNode = new BoxShadowNode();
const auto& shadowMetrics = box->shadow();
auto shadowNode = QskSGNode::ensureNode< QskBoxShadowNode >( node );
shadowNode->setRect( shadowMetrics.shadowRect( r ) );
shadowNode->setShape( box->shape() );
shadowNode->setBlurRadius( shadowMetrics.blurRadius() );
@ -69,15 +65,11 @@ namespace
return shadowNode;
}
#endif
case PanelRole:
{
auto boxNode = static_cast< QskBoxNode* >( node );
if ( boxNode == nullptr )
boxNode = new QskBoxNode();
const auto r = box->subControlRect( ShadowedBox::Panel );
auto boxNode = QskSGNode::ensureNode< QskBoxNode >( node );
boxNode->setBoxData( r, box->shape(), box->borderWidth(),
box->borderColor(), box->gradient() );

View File

@ -64,16 +64,6 @@ HEADERS += \
nodes/DiagramSegmentsNode.h \
nodes/RadialTickmarksNode.h
lessThan(QT_MAJOR_VERSION, 6) {
# the shader for the drop shadows has not yet been migrated
# to work with Qt 6
SOURCES += nodes/BoxShadowNode.cpp
HEADERS += nodes/BoxShadowNode.h
}
RESOURCES += \
images.qrc \
fonts.qrc \
shaders.qrc
fonts.qrc

View File

@ -1,256 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "BoxShadowNode.h"
#include "QskBoxShapeMetrics.h"
#include <QColor>
#include <QSGMaterialShader>
#include <QSGMaterial>
#include <private/qsgnode_p.h>
namespace
{
class Shader final : public QSGMaterialShader
{
public:
Shader();
char const* const* attributeNames() const override;
void initialize() override;
void updateState( const QSGMaterialShader::RenderState& state,
QSGMaterial* newMaterial, QSGMaterial* oldMaterial) override;
private:
int m_matrixId = -1;
int m_opacityId = -1;
int m_aspectId = -1;
int m_blurExtentId = -1;
int m_radiusId = -1;
int m_colorId = -1;
};
class Material final : public QSGMaterial
{
public:
Material();
QSGMaterialShader* createShader() const override;
QSGMaterialType* type() const override;
int compare( const QSGMaterial* other ) const override;
QVector2D aspect = QVector2D{ 1.0, 1.0 };
float blurExtent = 0.0;
QVector4D radius = QVector4D{ 0.0, 0.0, 0.0, 0.0 };
QColor color = Qt::black;
};
Shader::Shader()
{
const QString root( ":/iotdashboard/shaders/" );
setShaderSourceFile( QOpenGLShader::Vertex, root + "boxshadow.vert" );
setShaderSourceFile( QOpenGLShader::Fragment, root + "boxshadow.frag" );
}
char const* const* Shader::attributeNames() const
{
static char const* const names[] = { "in_vertex", "in_coord", nullptr };
return names;
}
void Shader::initialize()
{
QSGMaterialShader::initialize();
auto p = program();
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" );
}
void Shader::updateState( const QSGMaterialShader::RenderState& state,
QSGMaterial* newMaterial, QSGMaterial* oldMaterial )
{
auto p = program();
if ( state.isMatrixDirty() )
p->setUniformValue( m_matrixId, state.combinedMatrix() );
if ( state.isOpacityDirty() )
p->setUniformValue( m_opacityId, state.opacity() );
if ( oldMaterial == nullptr || newMaterial->compare( oldMaterial ) != 0 )
{
auto material = static_cast< const Material* >( newMaterial );
p->setUniformValue( m_aspectId, material->aspect );
p->setUniformValue( m_blurExtentId, material->blurExtent);
p->setUniformValue( m_radiusId, material->radius );
p->setUniformValue( m_colorId, material->color );
}
}
Material::Material()
{
setFlag( QSGMaterial::Blending, true );
}
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
&& qFuzzyCompare(material->blurExtent, blurExtent)
&& 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 );
if ( rect == d->rect )
return;
d->rect = rect;
QVector2D aspect( 1.0, 1.0 );
if ( rect.width() >= rect.height() )
aspect.setX( rect.width() / rect.height() );
else
aspect.setY( rect.height() / rect.width() );
if ( d->material.aspect != aspect )
{
d->material.aspect = aspect;
markDirty( QSGNode::DirtyMaterial );
}
}
void BoxShadowNode::setShape( const QskBoxShapeMetrics& shape )
{
Q_D( BoxShadowNode );
const float t = std::min( d->rect.width(), d->rect.height() );
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 );
if ( d->material.color != c )
{
d->material.color = c;
markDirty( QSGNode::DirtyMaterial );
}
}
void BoxShadowNode::setBlurRadius( qreal blurRadius )
{
Q_D( BoxShadowNode );
if ( blurRadius <= 0.0 )
blurRadius = 0.0;
const float t = 0.5 * std::min( d->rect.width(), d->rect.height() );
const float uniformExtent = blurRadius / t;
if ( !qFuzzyCompare( d->material.blurExtent, uniformExtent ) )
{
d->material.blurExtent = uniformExtent;
markDirty( QSGNode::DirtyMaterial );
}
}
void BoxShadowNode::setClipRect( const QRectF& rect )
{
Q_UNUSED( rect )
}
void BoxShadowNode::updateGeometry()
{
Q_D( BoxShadowNode );
QSGGeometry::updateTexturedRectGeometry(
&d->geometry, d->rect, QRectF( -0.5, -0.5, 1.0, 1.0 ) );
markDirty( QSGNode::DirtyGeometry );
}

View File

@ -7,13 +7,7 @@ SUBDIRS += \
inputpanel \
images
lessThan(QT_MAJOR_VERSION, 6) {
# the shader for the drop shadows has not yet been migrated
# to work with Qt 6
SUBDIRS += shadows
}
SUBDIRS += shadows
qtHaveModule(webengine) {

View File

@ -1,261 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "BoxShadowNode.h"
#include "QskBoxShapeMetrics.h"
#include <QColor>
#include <QSGMaterialShader>
#include <QSGMaterial>
#include <private/qsgnode_p.h>
namespace
{
class Shader final : public QSGMaterialShader
{
public:
Shader();
char const* const* attributeNames() const override;
void initialize() override;
void updateState( const QSGMaterialShader::RenderState& state,
QSGMaterial* newMaterial, QSGMaterial* oldMaterial) override;
private:
int m_matrixId = -1;
int m_opacityId = -1;
int m_aspectId = -1;
int m_blurExtentId = -1;
int m_radiusId = -1;
int m_colorId = -1;
};
class Material final : public QSGMaterial
{
public:
Material();
QSGMaterialShader* createShader() const override;
QSGMaterialType* type() const override;
int compare( const QSGMaterial* other ) const override;
QVector2D aspect = QVector2D{ 1.0, 1.0 };
float blurExtent = 0.0;
QVector4D radius = QVector4D{ 0.0, 0.0, 0.0, 0.0 };
QColor color = Qt::black;
};
Shader::Shader()
{
const QString root( ":/qskinny/shaders/" );
setShaderSourceFile( QOpenGLShader::Vertex, root + "boxshadow.vert" );
setShaderSourceFile( QOpenGLShader::Fragment, root + "boxshadow.frag" );
}
char const* const* Shader::attributeNames() const
{
static char const* const names[] = { "in_vertex", "in_coord", nullptr };
return names;
}
void Shader::initialize()
{
QSGMaterialShader::initialize();
auto p = program();
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" );
}
void Shader::updateState( const QSGMaterialShader::RenderState& state,
QSGMaterial* newMaterial, QSGMaterial* oldMaterial )
{
auto p = program();
if ( state.isMatrixDirty() )
p->setUniformValue( m_matrixId, state.combinedMatrix() );
if ( state.isOpacityDirty() )
p->setUniformValue( m_opacityId, state.opacity() );
bool updateMaterial = ( oldMaterial == nullptr )
|| newMaterial->compare( oldMaterial ) != 0;
updateMaterial |= state.isCachedMaterialDataDirty();
if ( updateMaterial )
{
auto material = static_cast< const Material* >( newMaterial );
p->setUniformValue( m_aspectId, material->aspect );
p->setUniformValue( m_blurExtentId, material->blurExtent);
p->setUniformValue( m_radiusId, material->radius );
p->setUniformValue( m_colorId, material->color );
}
}
Material::Material()
{
setFlag( QSGMaterial::Blending, true );
}
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
&& qFuzzyCompare(material->blurExtent, blurExtent)
&& 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 );
if ( rect == d->rect )
return;
d->rect = rect;
QVector2D aspect( 1.0, 1.0 );
if ( rect.width() >= rect.height() )
aspect.setX( rect.width() / rect.height() );
else
aspect.setY( rect.height() / rect.width() );
if ( d->material.aspect != aspect )
{
d->material.aspect = aspect;
markDirty( QSGNode::DirtyMaterial );
}
}
void BoxShadowNode::setShape( const QskBoxShapeMetrics& shape )
{
Q_D( BoxShadowNode );
const float t = std::min( d->rect.width(), d->rect.height() );
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 );
if ( d->material.color != c )
{
d->material.color = c;
markDirty( QSGNode::DirtyMaterial );
}
}
void BoxShadowNode::setBlurRadius( qreal blurRadius )
{
Q_D( BoxShadowNode );
if ( blurRadius <= 0.0 )
blurRadius = 0.0;
const float t = 0.5 * std::min( d->rect.width(), d->rect.height() );
const float uniformExtent = blurRadius / t;
if ( !qFuzzyCompare( d->material.blurExtent, uniformExtent ) )
{
d->material.blurExtent = uniformExtent;
markDirty( QSGNode::DirtyMaterial );
}
}
void BoxShadowNode::setClipRect( const QRectF& rect )
{
Q_UNUSED( rect )
}
void BoxShadowNode::updateGeometry()
{
Q_D( BoxShadowNode );
QSGGeometry::updateTexturedRectGeometry(
&d->geometry, d->rect, QRectF( -0.5, -0.5, 1.0, 1.0 ) );
markDirty( QSGNode::DirtyGeometry );
}

View File

@ -1,32 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
#include <QSGGeometryNode>
class QColor;
class QskBoxShapeMetrics;
class BoxShadowNodePrivate;
class BoxShadowNode : public QSGGeometryNode
{
public:
BoxShadowNode();
~BoxShadowNode() override;
void setRect( const QRectF& );
void setShape( const QskBoxShapeMetrics& );
void setColor( const QColor& );
void setBlurRadius( qreal );
void setClipRect( const QRectF& );
void updateGeometry();
private:
Q_DECLARE_PRIVATE( BoxShadowNode )
};

View File

@ -4,9 +4,10 @@
*****************************************************************************/
#include "ShadowedBox.h"
#include "BoxShadowNode.h"
#include <QskBoxNode.h>
#include <QskBoxShadowNode.h>
#include <QskSGNode.h>
#include <QskBoxBorderMetrics.h>
#include <QskBoxBorderColors.h>
#include <QskGradient.h>
@ -49,12 +50,10 @@ namespace
{
case ShadowRole:
{
auto shadowNode = static_cast< BoxShadowNode* >( node );
if ( shadowNode == nullptr )
shadowNode = new BoxShadowNode();
const auto& shadowMetrics = box->shadow();
auto shadowNode = QskSGNode::ensureNode< QskBoxShadowNode >( node );
shadowNode->setRect( shadowMetrics.shadowRect( r ) );
shadowNode->setShape( box->shape() );
shadowNode->setBlurRadius( shadowMetrics.blurRadius() );

View File

@ -1,7 +0,0 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/qskinny/shaders">
<file>boxshadow.vert</file>
<file>boxshadow.frag</file>
</qresource>
</RCC>

View File

@ -1,14 +1,8 @@
CONFIG += qskexample
QT += quick_private
RESOURCES += \
shaders.qrc
HEADERS += \
ShadowedBox.h \
BoxShadowNode.h
SOURCES += \
ShadowedBox.cpp \
BoxShadowNode.cpp \
main.cpp

View File

@ -0,0 +1,365 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskBoxShadowNode.h"
#include "QskBoxShapeMetrics.h"
#include <qcolor.h>
#include <qsgmaterialshader.h>
#include <qsgmaterial.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
QSK_QT_PRIVATE_END
// QSGMaterialRhiShader became QSGMaterialShader in Qt6
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
#include <QSGMaterialRhiShader>
using RhiShader = QSGMaterialRhiShader;
#else
using RhiShader = QSGMaterialShader;
#endif
namespace
{
class Material final : public QSGMaterial
{
public:
Material();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QSGMaterialShader* createShader() const override;
#else
QSGMaterialShader* createShader( QSGRendererInterface::RenderMode ) const override;
#endif
QSGMaterialType* type() const override;
int compare( const QSGMaterial* other ) const override;
QVector2D m_aspect = QVector2D{ 1, 1 };
QVector4D m_radius = QVector4D{ 0, 0, 0, 0 };
QVector4D m_color = QVector4D{ 0, 0, 0, 1 };
float m_blurExtent = 0.0;
};
}
namespace
{
class ShaderRhi final : public RhiShader
{
public:
ShaderRhi()
{
const QString root( ":/qskinny/shaders/" );
setShaderFileName( VertexStage, root + "boxshadow.vert.qsb" );
setShaderFileName( FragmentStage, root + "boxshadow.frag.qsb" );
}
bool updateUniformData( RenderState& state,
QSGMaterial* newMaterial, QSGMaterial* oldMaterial ) override
{
const auto matOld = static_cast< Material* >( oldMaterial );
const auto matNew = static_cast< Material* >( newMaterial );
Q_ASSERT( state.uniformData()->size() >= 112 );
auto data = state.uniformData()->data();
bool changed = false;
if ( state.isMatrixDirty() )
{
const auto matrix = state.combinedMatrix();
memcpy( data + 0, matrix.constData(), 64 );
changed = true;
}
if ( matOld == nullptr || matNew->m_color != matOld->m_color )
{
memcpy( data + 64, &matNew->m_color, 16 );
changed = true;
}
if ( matOld == nullptr || matNew->m_radius != matOld->m_radius )
{
memcpy( data + 80, &matNew->m_radius, 16 );
changed = true;
}
if ( matOld == nullptr || matNew->m_aspect != matOld->m_aspect )
{
memcpy( data + 96, &matNew->m_aspect, 8 );
changed = true;
}
if ( matOld == nullptr || matNew->m_blurExtent != matOld->m_blurExtent )
{
memcpy( data + 104, &matNew->m_blurExtent, 4 );
changed = true;
}
if ( state.isOpacityDirty() )
{
const float opacity = state.opacity();
memcpy( data + 108, &opacity, 4 );
changed = true;
}
return changed;
}
};
}
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
namespace
{
// the old type of shader - spcific for OpenGL
class ShaderGL final : public QSGMaterialShader
{
public:
ShaderGL()
{
const QString root( ":/qskinny/shaders/" );
setShaderSourceFile( QOpenGLShader::Vertex, root + "boxshadow.vert" );
setShaderSourceFile( QOpenGLShader::Fragment, root + "boxshadow.frag" );
}
char const* const* attributeNames() const override
{
static char const* const names[] = { "in_vertex", "in_coord", nullptr };
return names;
}
void initialize() override
{
QSGMaterialShader::initialize();
auto p = program();
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" );
}
void updateState( const QSGMaterialShader::RenderState& state,
QSGMaterial* newMaterial, QSGMaterial* oldMaterial) override
{
auto p = program();
if ( state.isMatrixDirty() )
p->setUniformValue( m_matrixId, state.combinedMatrix() );
if ( state.isOpacityDirty() )
p->setUniformValue( m_opacityId, state.opacity() );
bool updateMaterial = ( oldMaterial == nullptr )
|| newMaterial->compare( oldMaterial ) != 0;
updateMaterial |= state.isCachedMaterialDataDirty();
if ( updateMaterial )
{
auto material = static_cast< const Material* >( newMaterial );
p->setUniformValue( m_aspectId, material->m_aspect );
p->setUniformValue( m_blurExtentId, material->m_blurExtent);
p->setUniformValue( m_radiusId, material->m_radius );
p->setUniformValue( m_colorId, material->m_color );
}
}
private:
int m_matrixId = -1;
int m_opacityId = -1;
int m_aspectId = -1;
int m_blurExtentId = -1;
int m_radiusId = -1;
int m_colorId = -1;
};
}
#endif
Material::Material()
{
setFlag( QSGMaterial::Blending, true );
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
setFlag( QSGMaterial::SupportsRhiShader, true );
#endif
}
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QSGMaterialShader* Material::createShader() const
{
if ( !( flags() & QSGMaterial::RhiShaderWanted ) )
return new ShaderGL();
return new ShaderRhi();
}
#else
QSGMaterialShader* Material::createShader( QSGRendererInterface::RenderMode ) const
{
return new ShaderRhi();
}
#endif
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->m_color != m_color
|| material->m_aspect != m_aspect
|| !qFuzzyCompare(material->m_blurExtent, m_blurExtent)
|| !qFuzzyCompare(material->m_radius, m_radius) )
{
return 1;
}
return QSGMaterial::compare( other );
}
class QskBoxShadowNodePrivate final : public QSGGeometryNodePrivate
{
public:
QskBoxShadowNodePrivate()
: geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 )
{
}
QSGGeometry geometry;
Material material;
QRectF rect;
};
QskBoxShadowNode::QskBoxShadowNode()
: QSGGeometryNode( *new QskBoxShadowNodePrivate )
{
Q_D( QskBoxShadowNode );
setGeometry( &d->geometry );
setMaterial( &d->material );
}
QskBoxShadowNode::~QskBoxShadowNode()
{
}
void QskBoxShadowNode::setRect( const QRectF& rect )
{
Q_D( QskBoxShadowNode );
if ( rect == d->rect )
return;
d->rect = rect;
QVector2D aspect( 1.0, 1.0 );
if ( rect.width() >= rect.height() )
aspect.setX( rect.width() / rect.height() );
else
aspect.setY( rect.height() / rect.width() );
if ( d->material.m_aspect != aspect )
{
d->material.m_aspect = aspect;
markDirty( QSGNode::DirtyMaterial );
}
}
void QskBoxShadowNode::setShape( const QskBoxShapeMetrics& shape )
{
Q_D( QskBoxShadowNode );
const float t = std::min( d->rect.width(), d->rect.height() );
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.m_radius != uniformRadius )
{
d->material.m_radius = uniformRadius;
markDirty( QSGNode::DirtyMaterial );
}
}
void QskBoxShadowNode::setColor( const QColor& color )
{
Q_D( QskBoxShadowNode );
const auto a = color.alphaF();
const QVector4D c( color.redF() * a, color.greenF() * a, color.blueF() * a, a );
if ( d->material.m_color != c )
{
d->material.m_color = c;
markDirty( QSGNode::DirtyMaterial );
}
}
void QskBoxShadowNode::setBlurRadius( qreal blurRadius )
{
Q_D( QskBoxShadowNode );
if ( blurRadius <= 0.0 )
blurRadius = 0.0;
const float t = 0.5 * std::min( d->rect.width(), d->rect.height() );
const float uniformExtent = blurRadius / t;
if ( !qFuzzyCompare( d->material.m_blurExtent, uniformExtent ) )
{
d->material.m_blurExtent = uniformExtent;
markDirty( QSGNode::DirtyMaterial );
}
}
void QskBoxShadowNode::setClipRect( const QRectF& )
{
/*
Usually only the parts, that are not covered by the related rectangle
should be painted. TODO ...
*/
}
void QskBoxShadowNode::updateGeometry()
{
Q_D( QskBoxShadowNode );
QSGGeometry::updateTexturedRectGeometry(
&d->geometry, d->rect, QRectF( -0.5, -0.5, 1.0, 1.0 ) );
markDirty( QSGNode::DirtyGeometry );
}

View File

@ -1,32 +1,35 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#pragma once
#ifndef QSK_BOX_SHADOW_NODE_H
#define QSK_BOX_SHADOW_NODE_H
#include "QskGlobal.h"
#include <QSGGeometryNode>
class QColor;
class QskBoxShapeMetrics;
class BoxShadowNodePrivate;
class QskBoxShadowNodePrivate;
class BoxShadowNode : public QSGGeometryNode
class QSK_EXPORT QskBoxShadowNode : public QSGGeometryNode
{
public:
BoxShadowNode();
~BoxShadowNode() override;
QskBoxShadowNode();
~QskBoxShadowNode() override;
void setRect( const QRectF& );
void setShape( const QskBoxShapeMetrics& );
void setColor( const QColor& );
void setBlurRadius( qreal );
void updateGeometry();
void setClipRect( const QRectF& );
void updateGeometry();
private:
Q_DECLARE_PRIVATE( BoxShadowNode )
Q_DECLARE_PRIVATE( QskBoxShadowNode )
};
#endif

9
src/nodes/shaders.qrc Normal file
View File

@ -0,0 +1,9 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/qskinny/">
<file>shaders/boxshadow.vert.qsb</file>
<file>shaders/boxshadow.frag.qsb</file>
<file>shaders/boxshadow.vert</file>
<file>shaders/boxshadow.frag</file>
</qresource>
</RCC>

View File

@ -0,0 +1,49 @@
#version 440
layout(location = 0) in vec2 coord;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf
{
mat4 matrix;
vec4 color;
vec4 radius;
vec2 aspect;
float blurExtent;
float opacity;
} ubuf;
float effectiveRadius( in vec4 radii, in vec2 point )
{
if ( point.x > 0.0 )
return ( point.y > 0.0) ? radii.x : radii.y;
else
return ( point.y > 0.0) ? radii.z : radii.w;
}
void main()
{
vec4 col = vec4(0.0);
if ( ubuf.opacity > 0.0 )
{
const float minRadius = 0.05;
float e2 = 0.5 * ubuf.blurExtent;
float r = 2.0 * effectiveRadius( ubuf.radius, coord );
float f = minRadius / max( r, minRadius );
r += e2 * f;
vec2 d = r + ubuf.blurExtent - ubuf.aspect * ( 1.0 - abs( 2.0 * coord ) );
float l = min( max(d.x, d.y), 0.0) + length( max(d, 0.0) );
float shadow = l - r;
float v = smoothstep( -e2, e2, shadow );
col = mix( ubuf.color, vec4(0.0), v ) * ubuf.opacity;
}
fragColor = col;
}

View File

@ -0,0 +1,24 @@
#version 440
layout(location = 0) in vec4 in_vertex;
layout(location = 1) in vec2 in_coord;
layout(location = 0) out vec2 coord;
layout(std140, binding = 0) uniform buf
{
mat4 matrix;
vec4 color;
vec4 radius;
vec2 aspect;
float blurExtent;
float opacity;
} ubuf;
out gl_PerVertex { vec4 gl_Position; };
void main()
{
coord = in_coord;
gl_Position = ubuf.matrix * in_vertex;
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,4 @@
#! /bin/sh
qsb --glsl 100es,120,150 --hlsl 50 --msl 12 -b -o boxshadow.vert.qsb boxshadow-vulkan.vert
qsb --glsl 100es,120,150 --hlsl 50 --msl 12 -b -o boxshadow.frag.qsb boxshadow-vulkan.frag

View File

@ -103,6 +103,7 @@ HEADERS += \
nodes/QskBoxClipNode.h \
nodes/QskBoxRenderer.h \
nodes/QskBoxRendererColorMap.h \
nodes/QskBoxShadowNode.h \
nodes/QskGraphicNode.h \
nodes/QskPaintedNode.h \
nodes/QskPlainTextRenderer.h \
@ -123,6 +124,7 @@ SOURCES += \
nodes/QskBoxRendererRect.cpp \
nodes/QskBoxRendererEllipse.cpp \
nodes/QskBoxRendererDEllipse.cpp \
nodes/QskBoxShadowNode.cpp \
nodes/QskGraphicNode.cpp \
nodes/QskPaintedNode.cpp \
nodes/QskPlainTextRenderer.cpp \
@ -135,6 +137,9 @@ SOURCES += \
nodes/QskTickmarksNode.cpp \
nodes/QskVertex.cpp
RESOURCES += \
nodes/shaders.qrc
HEADERS += \
controls/QskAbstractButton.h \
controls/QskAnimationHint.h \
@ -364,6 +369,7 @@ SOURCES += \
inputpanel/QskInputPredictionBar.cpp \
inputpanel/QskVirtualKeyboard.cpp
pinyin {
unix {