From e63b064f5aa829161ffccd6df78fbe947614e083 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sat, 6 Jan 2024 15:05:30 +0100 Subject: [PATCH] QskArcShadowNode introduced ( kudos to Rick ) --- playground/shadows/ArcPage.cpp | 109 +++++++ playground/shadows/ArcPage.h | 14 + playground/shadows/BoxPage.cpp | 73 +++++ playground/shadows/BoxPage.h | 19 ++ playground/shadows/CMakeLists.txt | 5 +- playground/shadows/ShadowedArc.cpp | 269 +++++++++++++++++ playground/shadows/ShadowedArc.h | 64 +++++ playground/shadows/ShadowedBox.cpp | 13 +- playground/shadows/Slider.cpp | 47 +++ playground/shadows/Slider.h | 37 +++ playground/shadows/main.cpp | 132 ++------- src/CMakeLists.txt | 2 + src/controls/QskSkinlet.cpp | 8 +- src/nodes/QskArcNode.cpp | 94 ++++-- src/nodes/QskArcNode.h | 6 + src/nodes/QskArcShadowNode.cpp | 368 ++++++++++++++++++++++++ src/nodes/QskArcShadowNode.h | 32 +++ src/nodes/QskBoxShadowNode.cpp | 24 +- src/nodes/shaders.qrc | 5 + src/nodes/shaders/arcshadow-vulkan.frag | 46 +++ src/nodes/shaders/arcshadow-vulkan.vert | 21 ++ src/nodes/shaders/arcshadow.frag | 37 +++ src/nodes/shaders/arcshadow.frag.qsb | Bin 0 -> 2282 bytes src/nodes/shaders/arcshadow.vert | 12 + src/nodes/shaders/arcshadow.vert.qsb | Bin 0 -> 1585 bytes src/nodes/shaders/arcshadow2qsb.sh | 10 + src/nodes/shaders/boxshadow-vulkan.frag | 26 +- src/nodes/shaders/boxshadow-vulkan.vert | 2 +- src/nodes/shaders/boxshadow.frag | 26 +- src/nodes/shaders/boxshadow.frag.qsb | Bin 2656 -> 2606 bytes src/nodes/shaders/boxshadow.vert.qsb | Bin 1559 -> 1576 bytes src/nodes/shaders/vulkan2qsb.sh | 3 + 32 files changed, 1310 insertions(+), 194 deletions(-) create mode 100644 playground/shadows/ArcPage.cpp create mode 100644 playground/shadows/ArcPage.h create mode 100644 playground/shadows/BoxPage.cpp create mode 100644 playground/shadows/BoxPage.h create mode 100644 playground/shadows/ShadowedArc.cpp create mode 100644 playground/shadows/ShadowedArc.h create mode 100644 playground/shadows/Slider.cpp create mode 100644 playground/shadows/Slider.h create mode 100644 src/nodes/QskArcShadowNode.cpp create mode 100644 src/nodes/QskArcShadowNode.h create mode 100644 src/nodes/shaders/arcshadow-vulkan.frag create mode 100644 src/nodes/shaders/arcshadow-vulkan.vert create mode 100644 src/nodes/shaders/arcshadow.frag create mode 100644 src/nodes/shaders/arcshadow.frag.qsb create mode 100644 src/nodes/shaders/arcshadow.vert create mode 100644 src/nodes/shaders/arcshadow.vert.qsb create mode 100755 src/nodes/shaders/arcshadow2qsb.sh diff --git a/playground/shadows/ArcPage.cpp b/playground/shadows/ArcPage.cpp new file mode 100644 index 000000000..7ee255327 --- /dev/null +++ b/playground/shadows/ArcPage.cpp @@ -0,0 +1,109 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "ArcPage.h" +#include "ShadowedArc.h" +#include "Slider.h" + +#include + +namespace +{ + class ControlPanel : public QskGridBox + { + Q_OBJECT + + public: + ControlPanel( ShadowedArc* arc, QQuickItem* parent = nullptr ) + : QskGridBox( parent ) + { + setMargins( 5 ); + setSpacing( 10 ); + + { + auto slider = new Slider( "Start", 0, 360, 10, arc->startAngle() ); + connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setStartAngle ); + + addItem( slider, 0, 0 ); + } + { + auto slider = new Slider( "Span", -360, 360, 10, arc->spanAngle() ); + connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setSpanAngle ); + + addItem( slider, 0, 1 ); + } + { + auto slider = new Slider( "Extent", 0, 100, 1, arc->thickness() ); + connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setThickness ); + + addItem( slider, 1, 0 ); + } + { + auto slider = new Slider( "Border", 0, 10, 1, arc->borderWidth() ); + connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setBorderWidth ); + + addItem( slider, 1, 1); + } + { + auto slider = new Slider( "Spread Radius", -10, 50, 1, arc->spreadRadius() ); + connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setSpreadRadius ); + + addItem( slider, 2, 0 ); + } + { + auto slider = new Slider( "Blur Radius", 0, 50, 1, arc->blurRadius() ); + connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setBlurRadius ); + + addItem( slider, 2, 1 ); + } + { + auto slider = new Slider( "Offset X", -50, 50, 1, arc->offsetX() ); + connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setOffsetX ); + + addItem( slider, 3, 0 ); + + } + { + auto slider = new Slider( "Offset Y", -50, 50, 1, arc->offsetY() ); + connect( slider, &Slider::valueChanged, arc, &ShadowedArc::setOffsetY ); + + addItem( slider, 3, 1 ); + } + } + }; +} + +ArcPage::ArcPage( QQuickItem* parent ) + : QskLinearBox( Qt::Vertical, parent ) +{ + auto arc = new ShadowedArc(); + arc->setMargins( 40 ); // some extra space for testing the offsets + + { + // initial settings + arc->setStartAngle( 45.0 ); + arc->setSpanAngle( 270.0 ); + arc->setThickness( 10.0 ); + + arc->setFillColor( Qt::darkRed ); + + arc->setBorderWidth( 0 ); + arc->setBorderColor( Qt::darkYellow ); + + arc->setShadowColor( Qt::black ); + arc->setSpreadRadius( 0.0 ); + arc->setBlurRadius( 4.0 ); + arc->setOffsetX( 2.0 ); + arc->setOffsetY( 2.0 ); + } + + auto panel = new ControlPanel( arc ); + panel->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed ); + + addItem( panel ); + addItem( arc ); +} + +#include "ArcPage.moc" diff --git a/playground/shadows/ArcPage.h b/playground/shadows/ArcPage.h new file mode 100644 index 000000000..eeb620668 --- /dev/null +++ b/playground/shadows/ArcPage.h @@ -0,0 +1,14 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#pragma once + +#include + +class ArcPage : public QskLinearBox +{ + public: + ArcPage( QQuickItem* parent = nullptr ); +}; diff --git a/playground/shadows/BoxPage.cpp b/playground/shadows/BoxPage.cpp new file mode 100644 index 000000000..860c2c0f2 --- /dev/null +++ b/playground/shadows/BoxPage.cpp @@ -0,0 +1,73 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "BoxPage.h" +#include "ShadowedBox.h" +#include "Slider.h" + +#include +#include + +namespace +{ + class ControlPanel : public QskLinearBox + { + public: + ControlPanel( ShadowedBox* box, QQuickItem* parent = nullptr ) + : QskLinearBox( Qt::Vertical, parent ) + { + { + auto slider = new Slider( "Offset X", -50, 50, 1, box->offsetX() ); + connect( slider, &Slider::valueChanged, box, &ShadowedBox::setOffsetX ); + + addItem( slider ); + } + { + auto slider = new Slider( "Offset Y", -50, 50, 1, box->offsetY() ); + connect( slider, &Slider::valueChanged, box, &ShadowedBox::setOffsetY ); + + addItem( slider ); + } + { + auto slider = new Slider( "Spread Radius", -10, 50, 1, box->spreadRadius() ); + connect( slider, &Slider::valueChanged, box, &ShadowedBox::setSpreadRadius ); + + addItem( slider ); + } + { + auto slider = new Slider( "Blur Radius", 0, 50, 1, box->blurRadius() ); + connect( slider, &Slider::valueChanged, box, &ShadowedBox::setBlurRadius ); + + addItem( slider ); + } + { + auto slider = new Slider( "Opacity", 0, 1, 0.01, box->opacity() ); + connect( slider, &Slider::valueChanged, box, &ShadowedBox::setOpacity ); + + addItem( slider ); + } + } + }; +} + +BoxPage::BoxPage( QQuickItem* parent ) + : QskLinearBox( Qt::Vertical, parent ) +{ + auto box = new ShadowedBox(); + box->setMargins( 40 ); // some extra space for testing the offsets + + { + box->setOffsetX( 10 ); + box->setOffsetY( 10 ); + box->setSpreadRadius( 0 ); + box->setBlurRadius( 5 ); + } + + auto panel = new ControlPanel( box ); + panel->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed ); + + addItem( panel ); + addItem( box ); +} diff --git a/playground/shadows/BoxPage.h b/playground/shadows/BoxPage.h new file mode 100644 index 000000000..d5dc15aa8 --- /dev/null +++ b/playground/shadows/BoxPage.h @@ -0,0 +1,19 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#pragma once + +#include + +class QskSlider; + +class BoxPage : public QskLinearBox +{ + public: + BoxPage( QQuickItem* parent = nullptr ); + + private: + void addSlider( int row, const QString&, QskSlider* ); +}; diff --git a/playground/shadows/CMakeLists.txt b/playground/shadows/CMakeLists.txt index 0d3466d70..f65ac3161 100644 --- a/playground/shadows/CMakeLists.txt +++ b/playground/shadows/CMakeLists.txt @@ -3,4 +3,7 @@ # SPDX-License-Identifier: BSD-3-Clause ############################################################################ -qsk_add_example(shadows ShadowedBox.h ShadowedBox.cpp main.cpp) +qsk_add_example(shadows + BoxPage.h BoxPage.cpp ShadowedBox.h ShadowedBox.cpp + ArcPage.h ArcPage.cpp ShadowedArc.h ShadowedArc.cpp + Slider.h Slider.cpp main.cpp) diff --git a/playground/shadows/ShadowedArc.cpp b/playground/shadows/ShadowedArc.cpp new file mode 100644 index 000000000..0ba49ad51 --- /dev/null +++ b/playground/shadows/ShadowedArc.cpp @@ -0,0 +1,269 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "ShadowedArc.h" + +#include +#include +#include +#include + +#include +#include + +QSK_SUBCONTROL( ShadowedArc, Arc ) + +namespace +{ + class Skinlet : public QskSkinlet + { + using Inherited = QskSkinlet; + + public: + enum NodeRoles { ArcRole }; + + Skinlet( QskSkin* skin = nullptr ); + + QRectF subControlRect( const QskSkinnable*, + const QRectF&, QskAspect::Subcontrol ) const override; + + QSGNode* updateSubNode( const QskSkinnable*, + quint8 nodeRole, QSGNode* ) const override; + + private: + QSGNode* updateArcNode( const ShadowedArc*, QSGNode* node ) const; + }; + + Skinlet::Skinlet( QskSkin* skin ) + : QskSkinlet( skin ) + { + setNodeRoles( { ArcRole } ); + } + + QRectF Skinlet::subControlRect( const QskSkinnable* skinnable, + const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const + { + if ( subControl == ShadowedArc::Arc ) + return contentsRect; + + return Inherited::subControlRect( skinnable, contentsRect, subControl ); + } + + QSGNode* Skinlet::updateSubNode( + const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const + { + if ( nodeRole == ArcRole ) + { + auto arc = static_cast< const ShadowedArc* >( skinnable ); + return updateArcNode( arc, node ); + } + + return Inherited::updateSubNode( skinnable, nodeRole, node ); + } + + QSGNode* Skinlet::updateArcNode( const ShadowedArc* arc, QSGNode* node ) const + { + using Q = ShadowedArc; + + const auto rect = arc->subControlRect( Q::Arc ); + if ( rect.isEmpty() ) + return nullptr; + + auto arcNode = QskSGNode::ensureNode< QskArcNode >( node ); + + const auto metrics = arc->arcMetricsHint( Q::Arc ); + const auto fillGradient = arc->gradientHint( Q::Arc ); + + const auto borderColor = arc->color( Q::Arc | QskAspect::Border ); + const auto borderWidth = arc->metric( Q::Arc | QskAspect::Border ); + + const auto shadowColor = arc->shadowColorHint( Q::Arc ); + const auto shadowMetrics = arc->shadowMetricsHint( Q::Arc ); + + arcNode->setArcData( rect, metrics, borderWidth, borderColor, + fillGradient, shadowColor, shadowMetrics); + + return arcNode; + } +} + +ShadowedArc::ShadowedArc( QQuickItem* parent ) + : Inherited( parent ) +{ + auto skinlet = new Skinlet(); + skinlet->setOwnedBySkinnable( true ); + + setSkinlet( skinlet ); + + // initial settings + + setArcMetrics( { 0.0, 360.0, 1.0, Qt::RelativeSize } ); + + setFillColor( Qt::darkRed ); + + setBorderWidth( 0 ); + setBorderColor( Qt::gray ); + + setShadowColor( Qt::black ); + setShadowMetrics( { 0, 0, QPointF( 0, 0 ), Qt::AbsoluteSize } ); +} + +ShadowedArc::~ShadowedArc() +{ +} + +void ShadowedArc::setThickness( qreal thickness ) +{ + auto metrics = arcMetrics(); + metrics.setThickness( thickness ); + + setArcMetrics( metrics ); +} + +qreal ShadowedArc::thickness() const +{ + return arcMetrics().thickness(); +} + +void ShadowedArc::setBorderWidth( qreal width ) +{ + width = std::max( width, 0.0 ); + setMetric( Arc | QskAspect::Border, width ); +} + +qreal ShadowedArc::borderWidth() const +{ + return metric( Arc | QskAspect::Border ); +} + +void ShadowedArc::setStartAngle( qreal degrees ) +{ + auto metrics = arcMetrics(); + metrics.setStartAngle( degrees ); + + setArcMetrics( metrics ); +} + +qreal ShadowedArc::startAngle() const +{ + return arcMetrics().startAngle(); +} + +void ShadowedArc::setSpanAngle( qreal degrees ) +{ + auto metrics = arcMetrics(); + metrics.setSpanAngle( degrees ); + + setArcMetrics( metrics ); +} + +qreal ShadowedArc::spanAngle() const +{ + return arcMetrics().spanAngle(); +} + +void ShadowedArc::setOffsetX( qreal dx ) +{ + auto metrics = shadowMetrics(); + metrics.setOffsetX( dx ); + + setShadowMetrics( metrics ); +} + +qreal ShadowedArc::offsetX() const +{ + return shadowMetrics().offset().x(); +} + +void ShadowedArc::setOffsetY( qreal dy ) +{ + auto metrics = shadowMetrics(); + metrics.setOffsetY( dy ); + + setShadowMetrics( metrics ); +} + +qreal ShadowedArc::offsetY() const +{ + return shadowMetrics().offset().y(); +} + +void ShadowedArc::setSpreadRadius( qreal radius ) +{ + auto metrics = shadowMetrics(); + metrics.setSpreadRadius( radius ); + + setShadowMetrics( metrics ); +} + +qreal ShadowedArc::spreadRadius() const +{ + return shadowMetrics().spreadRadius(); +} + +void ShadowedArc::setBlurRadius( qreal radius ) +{ + auto metrics = shadowMetrics(); + metrics.setBlurRadius( radius ); + + setShadowMetrics( metrics ); +} + +qreal ShadowedArc::blurRadius() const +{ + return shadowMetrics().blurRadius(); +} + +void ShadowedArc::setFillColor( const QColor& color ) +{ + setColor( Arc, color ); +} + +QColor ShadowedArc::fillColor() const +{ + return color( Arc ); +} + +void ShadowedArc::setShadowColor( const QColor& color ) +{ + setShadowColorHint( Arc, color ); +} + +QColor ShadowedArc::shadowColor() const +{ + return shadowColorHint( Arc ); +} + +void ShadowedArc::setBorderColor( const QColor& color ) +{ + setColor( Arc | QskAspect::Border, color ); +} + +QColor ShadowedArc::borderColor() const +{ + return color( Arc | QskAspect::Border ); +} + +QskShadowMetrics ShadowedArc::shadowMetrics() const +{ + return shadowMetricsHint( Arc ); +} + +void ShadowedArc::setShadowMetrics( const QskShadowMetrics& metrics ) +{ + setShadowMetricsHint( Arc, metrics ); +} + +QskArcMetrics ShadowedArc::arcMetrics() const +{ + return arcMetricsHint( Arc ); +} + +void ShadowedArc::setArcMetrics( const QskArcMetrics& metrics ) +{ + setArcMetricsHint( Arc, metrics ); +} + +#include "moc_ShadowedArc.cpp" diff --git a/playground/shadows/ShadowedArc.h b/playground/shadows/ShadowedArc.h new file mode 100644 index 000000000..a4179adef --- /dev/null +++ b/playground/shadows/ShadowedArc.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#pragma once + +#include + +class QskShadowMetrics; +class QskArcMetrics; + +class ShadowedArc : public QskControl +{ + Q_OBJECT + + using Inherited = QskControl; + + public: + QSK_SUBCONTROLS( Arc ) + + ShadowedArc( QQuickItem* parent = nullptr ); + ~ShadowedArc() override; + + qreal thickness() const; + qreal borderWidth() const; + + qreal startAngle() const; + qreal spanAngle() const; + + qreal offsetX() const; + qreal offsetY() const; + + qreal spreadRadius() const; + qreal blurRadius() const; + + QColor borderColor() const; + QColor fillColor() const; + QColor shadowColor() const; + + public Q_SLOTS: + void setThickness( qreal ); + void setBorderWidth( qreal ); + + void setStartAngle( qreal ); + void setSpanAngle( qreal ); + + void setOffsetX( qreal ); + void setOffsetY( qreal ); + + void setSpreadRadius( qreal ); + void setBlurRadius( qreal ); + + void setBorderColor( const QColor& ); + void setFillColor( const QColor& ); + void setShadowColor( const QColor& ); + + private: + QskShadowMetrics shadowMetrics() const; + void setShadowMetrics( const QskShadowMetrics& ); + + QskArcMetrics arcMetrics() const; + void setArcMetrics( const QskArcMetrics& ); +}; diff --git a/playground/shadows/ShadowedBox.cpp b/playground/shadows/ShadowedBox.cpp index 2431e80e3..cad0fd225 100644 --- a/playground/shadows/ShadowedBox.cpp +++ b/playground/shadows/ShadowedBox.cpp @@ -14,21 +14,10 @@ ShadowedBox::ShadowedBox( QQuickItem* parentItem ) : QskBox( true, parentItem ) { - QColor c( Qt::darkRed ); -#if 0 - c.setAlpha( 100 ); -#endif - - setGradientHint( Panel, c ); + setGradientHint( Panel, Qt::darkRed ); setBoxShapeHint( Panel, QskBoxShapeMetrics( 40, 0, 15, 0 ) ); setBoxBorderMetricsHint( Panel, 0 ); - -#if 0 - setBoxBorderMetricsHint( Panel, 10 ); - setBoxBorderColorsHint( Panel, Qt::blue ); -#endif - setShadowColorHint( Panel, Qt::black ); } diff --git a/playground/shadows/Slider.cpp b/playground/shadows/Slider.cpp new file mode 100644 index 000000000..0a08201a9 --- /dev/null +++ b/playground/shadows/Slider.cpp @@ -0,0 +1,47 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "Slider.h" + +#include +#include + +#include + +Slider::Slider( const QString& text, qreal min, qreal max, + qreal step, qreal value, QQuickItem* parent ) + : QskLinearBox( Qt::Horizontal, parent ) +{ + m_label = new QskTextLabel( text, this ); + m_label->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed ); + + m_slider = new QskSlider( this ); + m_slider->setBoundaries( min, max ); + m_slider->setStepSize( step ); + m_slider->setSnap( true ); + m_slider->setValue( value ); + + m_valueLabel = new QskTextLabel( this ); + m_valueLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); + updateLabel( value ); + + const QFontMetricsF fm( m_valueLabel->font() ); + m_valueLabel->setFixedWidth( fm.horizontalAdvance( "-100" ) ); + + connect( m_slider, &QskSlider::valueChanged, this, &Slider::updateLabel ); + connect( m_slider, &QskSlider::valueChanged, this, &Slider::valueChanged ); +} + +void Slider::updateLabel( qreal value ) +{ + m_valueLabel->setText( QString::number( value ) ); +} + +void Slider::setValue( qreal value ) +{ + m_slider->setValue( value ); +} + +#include "moc_Slider.cpp" diff --git a/playground/shadows/Slider.h b/playground/shadows/Slider.h new file mode 100644 index 000000000..c62fa1602 --- /dev/null +++ b/playground/shadows/Slider.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#pragma once + +#include + +class QskSlider; +class QskTextLabel; + +class Slider : public QskLinearBox +{ + Q_OBJECT + + using Inherited = QskLinearBox; + + public: + Slider( const QString&, qreal min, qreal max, qreal step, + qreal value, QQuickItem* parent = nullptr ); + + qreal value() const; + + Q_SIGNALS: + void valueChanged( qreal ); + + public Q_SLOTS: + void setValue( qreal ); + + private: + void updateLabel( qreal ); + + QskTextLabel* m_label = nullptr; + QskSlider* m_slider = nullptr; + QskTextLabel* m_valueLabel = nullptr; +}; diff --git a/playground/shadows/main.cpp b/playground/shadows/main.cpp index 2d6d6de9f..c4e2cedae 100644 --- a/playground/shadows/main.cpp +++ b/playground/shadows/main.cpp @@ -3,129 +3,31 @@ * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ -#include "ShadowedBox.h" +#include "BoxPage.h" +#include "ArcPage.h" #include #include -#include -#include -#include -#include +#include +#include #include #include -#include -class BoxPanel : public QskBox +namespace { - public: - BoxPanel( QQuickItem* parent = nullptr ) - : QskBox( parent ) + class TabView : public QskTabView { - setAutoLayoutChildren( true ); - setPadding( 60 ); - - setPanel( true ); - setGradientHint( QskBox::Panel, QGradient::SnowAgain ); - } -}; - -class Slider : public QskSlider -{ - public: - Slider( qreal min, qreal max, qreal step, qreal value, QQuickItem* parent = nullptr ) - : QskSlider( parent ) - { - setBoundaries( min, max ); - setStepSize( step ); - setSnap( true ); - setValue( value ); - } -}; - -class ValueLabel : public QskTextLabel -{ - public: - ValueLabel( QQuickItem* parent = nullptr ) - : QskTextLabel( parent ) - { - setFixedWidth( QFontMetrics( font() ).horizontalAdvance( "-100" ) ); - setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); - } - - void setValue( qreal value ) - { - setText( QString::number( value ) ); - } -}; - -class GridBox : public QskGridBox -{ - public: - GridBox( QQuickItem* parent = nullptr ) - : QskGridBox( parent ) - { - setPanel( true ); - setPadding( 5 ); - setColumnStretchFactor( 1, 1 ); - - auto sliderX = new Slider( -50, 50, 1, 10 ); - auto sliderY = new Slider( -50, 50, 1, 10 ); - auto sliderSpread = new Slider( 0, 50, 1, 0 ); - auto sliderBlur = new Slider( 0, 50, 1, 10 ); - auto sliderOpacity = new Slider( 0, 1, 0.01, 1 ); - - auto panel = new BoxPanel(); - - int row = 0; - - addSlider( row++, "Offset X", sliderX ); - addSlider( row++, "Offset Y", sliderY ); - addSlider( row++, "Spread Radius", sliderSpread ); - addSlider( row++, "Blur Radius", sliderBlur ); - addSlider( row++, "Opacity", sliderOpacity ); - - addItem( panel, row, 0, -1, -1 ); - - auto box = new ShadowedBox( panel ); - - box->setOffsetX( sliderX->value() ); - box->setOffsetY( sliderY->value() ); - box->setSpreadRadius( sliderSpread->value() ); - box->setBlurRadius( sliderBlur->value() ); - box->setOpacity( sliderOpacity->value() ); - - connect( sliderX, &QskSlider::valueChanged, - box, &ShadowedBox::setOffsetX ); - - connect( sliderY, &QskSlider::valueChanged, - box, &ShadowedBox::setOffsetY ); - - connect( sliderSpread, &QskSlider::valueChanged, - box, &ShadowedBox::setSpreadRadius ); - - connect( sliderBlur, &QskSlider::valueChanged, - box, &ShadowedBox::setBlurRadius ); - - connect( sliderOpacity, &QskSlider::valueChanged, - box, &ShadowedBox::setOpacity ); - } - - private: - void addSlider( int row, const QString& text, QskSlider* slider ) - { - addItem( new QskTextLabel( text ), row, 0 ); - addItem( slider, row, 1 ); - - auto label = new ValueLabel(); - label->setValue( slider->value() ); - - addItem( label, row, 2 ); - - connect( slider, &QskSlider::valueChanged, - label, [label]( qreal value ) { label->setText( QString::number( value ) ); } ); - } -}; + public: + TabView() + { + //setTabBarEdge( Qt::LeftEdge ); + + addTab( "Arc Shadow", new ArcPage() ); + addTab( "Box Shadow", new BoxPage() ); + } + }; +} int main( int argc, char* argv[] ) { @@ -138,7 +40,7 @@ int main( int argc, char* argv[] ) SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); QskWindow window; - window.addItem( new GridBox() ); + window.addItem( new TabView() ); window.resize( 600, 600 ); window.show(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3906ad948..3c6b49705 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -99,6 +99,7 @@ list(APPEND SOURCES list(APPEND HEADERS nodes/QskArcNode.h + nodes/QskArcShadowNode.h nodes/QskBasicLinesNode.h nodes/QskBoxNode.h nodes/QskBoxClipNode.h @@ -138,6 +139,7 @@ list(APPEND PRIVATE_HEADERS list(APPEND SOURCES nodes/QskArcNode.cpp + nodes/QskArcShadowNode.cpp nodes/QskBasicLinesNode.cpp nodes/QskBoxNode.cpp nodes/QskBoxClipNode.cpp diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index e63515192..1924339e5 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -231,7 +231,7 @@ static inline QSGNode* qskUpdateArcNode( return nullptr; auto arcNode = QskSGNode::ensureNode< QskArcNode >( node ); - arcNode->setArcData( rect, metrics, borderWidth, borderColor, gradient ); + arcNode->setArcData( rect, metrics, borderWidth, borderColor, gradient, {}, {} ); return arcNode; } @@ -547,11 +547,11 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable, } QSGNode* QskSkinlet::updateArcNode( - const QskSkinnable* skinnable, QSGNode* node, const QRectF& rect, + const QskSkinnable* skinnable, QSGNode* node, const QRectF& rect, qreal borderWidth, const QColor& borderColor, const QskGradient& fillGradient, const QskArcMetrics& metrics ) { - return qskUpdateArcNode( skinnable, node, rect, + return qskUpdateArcNode( skinnable, node, rect, borderWidth, borderColor, fillGradient, metrics ); } @@ -594,7 +594,7 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable, } QSGNode* QskSkinlet::updateLineNode( const QskSkinnable* skinnable, - QSGNode* node, const QLineF& line, QskAspect::Subcontrol subControl ) + QSGNode* node, const QLineF& line, QskAspect::Subcontrol subControl ) { auto lineStipple = skinnable->stippleMetricsHint( subControl ); if ( !lineStipple.isValid() ) diff --git a/src/nodes/QskArcNode.cpp b/src/nodes/QskArcNode.cpp index a58a72df4..ad280879a 100644 --- a/src/nodes/QskArcNode.cpp +++ b/src/nodes/QskArcNode.cpp @@ -5,15 +5,27 @@ #include "QskArcNode.h" #include "QskArcMetrics.h" +#include "QskArcShadowNode.h" #include "QskMargins.h" #include "QskGradient.h" #include "QskShapeNode.h" #include "QskStrokeNode.h" #include "QskSGNode.h" +#include "QskShadowMetrics.h" #include #include +namespace +{ + enum NodeRole + { + ShadowRole, + FillRole, + BorderRole + }; +} + static inline QskGradient qskEffectiveGradient( const QskGradient& gradient, const QskArcMetrics& metrics ) { @@ -54,6 +66,14 @@ static inline QRectF qskEffectiveRect( return qskValidOrEmptyInnerRect( rect, QskMargins( 0.5 * borderWidth ) ); } +static void qskUpdateChildren( QSGNode* parentNode, quint8 role, QSGNode* node ) +{ + static const QVector< quint8 > roles = { ShadowRole, FillRole, BorderRole }; + + auto oldNode = QskSGNode::findChildNode( parentNode, role ); + QskSGNode::replaceChildNode( roles, role, parentNode, oldNode, node ); +} + QskArcNode::QskArcNode() { } @@ -65,20 +85,24 @@ QskArcNode::~QskArcNode() void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics, const QskGradient& fillGradient ) { - setArcData( rect, arcMetrics, 0.0, QColor(), fillGradient ); + setArcData( rect, arcMetrics, 0.0, QColor(), fillGradient, {}, {} ); } void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics, - qreal borderWidth, const QColor& borderColor, const QskGradient& fillGradient ) + const qreal borderWidth, const QColor& borderColor, const QskGradient& fillGradient ) { - enum NodeRole - { - FillRole, - BorderRole - }; + setArcData( rect, arcMetrics, borderWidth, borderColor, fillGradient, {}, {} ); +} + +void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics, + const qreal borderWidth, const QColor& borderColor, const QskGradient& fillGradient, + const QColor& shadowColor, const QskShadowMetrics& shadowMetrics ) +{ + const auto metricsArc = qskEffectiveMetrics( arcMetrics, rect ); + const auto gradient = qskEffectiveGradient( fillGradient, metricsArc ); - const auto metrics = qskEffectiveMetrics( arcMetrics, rect ); - const auto gradient = qskEffectiveGradient( fillGradient, metrics ); + auto shadowNode = static_cast< QskArcShadowNode* >( + QskSGNode::findChildNode( this, ShadowRole ) ); auto fillNode = static_cast< QskShapeNode* >( QskSGNode::findChildNode( this, FillRole ) ); @@ -89,22 +113,52 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics const auto arcRect = qskEffectiveRect( rect, borderWidth ); if ( arcRect.isEmpty() ) { + delete shadowNode; delete fillNode; delete borderNode; - return; } - const auto path = metrics.painterPath( arcRect ); + const auto isFillNodeVisible = gradient.isVisible() && !metricsArc.isNull(); + const auto isStrokeNodeVisible = borderWidth > 0.0 && borderColor.alpha() > 0; + const auto isShadowNodeVisible = shadowColor.alpha() > 0.0 && isFillNodeVisible; - if ( gradient.isVisible() && !metrics.isNull() ) + const auto path = metricsArc.painterPath( arcRect ); + + if ( isShadowNodeVisible ) + { + if ( shadowNode == nullptr ) + { + shadowNode = new QskArcShadowNode; + QskSGNode::setNodeRole( shadowNode, ShadowRole ); + } + + /* + The shader of the shadow node is for circular arcs and we have some + unwanted scaling issues for the spread/blur values when having ellipsoid + arcs. We might also want to add the spread value to the ends of the arc + and not only to its radius. TODO ... + */ + + const auto sm = shadowMetrics.toAbsolute( arcRect.size() ); + const auto shadowRect = sm.shadowRect( arcRect ); + const auto spreadRadius = sm.spreadRadius() + 0.5 * metricsArc.thickness(); + + shadowNode->setShadowData( shadowRect, spreadRadius, sm.blurRadius(), + metricsArc.startAngle(), metricsArc.spanAngle(), shadowColor ); + } + else + { + delete shadowNode; + shadowNode = nullptr; + } + + if ( isFillNodeVisible ) { if ( fillNode == nullptr ) { fillNode = new QskShapeNode; QskSGNode::setNodeRole( fillNode, FillRole ); - - prependChildNode( fillNode ); } fillNode->updateNode( path, QTransform(), arcRect, gradient ); @@ -112,25 +166,29 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics else { delete fillNode; + fillNode = nullptr; } - if ( borderWidth > 0.0 && borderColor.alpha() > 0 ) + if ( isStrokeNodeVisible ) { if ( borderNode == nullptr ) { borderNode = new QskStrokeNode; QskSGNode::setNodeRole( borderNode, BorderRole ); - - appendChildNode( borderNode ); } QPen pen( borderColor, borderWidth ); pen.setCapStyle( Qt::FlatCap ); - + borderNode->updateNode( path, QTransform(), pen ); } else { delete borderNode; + borderNode = nullptr; } + + qskUpdateChildren(this, ShadowRole, shadowNode); + qskUpdateChildren(this, FillRole, fillNode); + qskUpdateChildren(this, BorderRole, borderNode); } diff --git a/src/nodes/QskArcNode.h b/src/nodes/QskArcNode.h index 1e3e44d1c..16784f2aa 100644 --- a/src/nodes/QskArcNode.h +++ b/src/nodes/QskArcNode.h @@ -10,6 +10,7 @@ class QskArcMetrics; class QskGradient; +class QskShadowMetrics; /* For the moment a QPainterPath/QskShapeNode. @@ -23,8 +24,13 @@ class QSK_EXPORT QskArcNode : public QskShapeNode ~QskArcNode() override; void setArcData( const QRectF&, const QskArcMetrics&, const QskGradient& ); + void setArcData( const QRectF&, const QskArcMetrics&, qreal borderWidth, const QColor& borderColor, const QskGradient& ); + + void setArcData( const QRectF&, const QskArcMetrics&, + qreal borderWidth, const QColor& borderColor, const QskGradient&, + const QColor& shadowColor, const QskShadowMetrics&); }; #endif diff --git a/src/nodes/QskArcShadowNode.cpp b/src/nodes/QskArcShadowNode.cpp new file mode 100644 index 000000000..8ced5062d --- /dev/null +++ b/src/nodes/QskArcShadowNode.cpp @@ -0,0 +1,368 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskArcShadowNode.h" + +#include +#include +#include +#include + +#include + +QSK_QT_PRIVATE_BEGIN +#include +QSK_QT_PRIVATE_END + +// QSGMaterialRhiShader became QSGMaterialShader in Qt6 + +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) +#include +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; + + QVector4D m_color { 0, 0, 0, 1 }; + QVector4D m_arc = {}; + + float m_spreadRadius = 0.0f; + float m_blurRadius = 0.0f; + }; +} + +namespace +{ + class ShaderRhi final : public RhiShader + { + public: + ShaderRhi() + { + const QString root( ":/qskinny/shaders/" ); + setShaderFileName( VertexStage, root + "arcshadow.vert.qsb" ); + setShaderFileName( FragmentStage, root + "arcshadow.frag.qsb" ); + } + + bool updateUniformData( RenderState& state, + QSGMaterial* const newMaterial, QSGMaterial* const oldMaterial ) override + { + const auto matOld = static_cast< Material* >( oldMaterial ); + const auto matNew = static_cast< Material* >( newMaterial ); + + Q_ASSERT( state.uniformData()->size() == 108 ); + + 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_arc != matOld->m_arc ) + { + memcpy( data + 80, &matNew->m_arc, 16 ); + changed = true; + } + + if ( matOld == nullptr || matNew->m_spreadRadius != matOld->m_spreadRadius ) + { + memcpy( data + 96, &matNew->m_spreadRadius, 4 ); + changed = true; + } + + if ( matOld == nullptr || matNew->m_blurRadius != matOld->m_blurRadius ) + { + memcpy( data + 100, &matNew->m_blurRadius, 4 ); + changed = true; + } + + if ( state.isOpacityDirty() ) + { + const float opacity = state.opacity(); + memcpy( data + 104, &opacity, 4 ); + + changed = true; + } + + return changed; + } + }; +} + +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + +namespace +{ + // the old type of shader - specific for OpenGL + + class ShaderGL final : public QSGMaterialShader + { + struct Uniforms + { + int matrix = -1; + int color = -1; + int arc = -1; + int spreadRadius = -1; + int blurRadius = -1; + int opacity = -1; + }; + + public: + ShaderGL() + { + const QString root( ":/qskinny/shaders/" ); + setShaderSourceFile( QOpenGLShader::Vertex, root + "arcshadow.vert" ); + setShaderSourceFile( QOpenGLShader::Fragment, root + "arcshadow.frag" ); + } + + char const* const* attributeNames() const override + { + static char const* const names[] = { "in_vertex", "in_coord", nullptr }; + return names; + } + + void initialize() override + { + QSGMaterialShader::initialize(); + + const auto* const p = program(); + + id.matrix = p->uniformLocation( "matrix" ); + id.color = p->uniformLocation( "color" ); + id.arc = p->uniformLocation( "arc" ); + id.spreadRadius = p->uniformLocation( "spreadRadius" ); + id.blurRadius = p->uniformLocation( "blurRadius" ); + id.opacity = p->uniformLocation( "opacity" ); + } + + void updateState( const QSGMaterialShader::RenderState& state, + QSGMaterial* const newMaterial, QSGMaterial* const oldMaterial ) override + { + auto* const p = program(); + + if ( state.isMatrixDirty() ) + { + p->setUniformValue( id.matrix, state.combinedMatrix() ); + } + + if ( state.isOpacityDirty() ) + { + p->setUniformValue( id.opacity, state.opacity() ); + } + + auto updateMaterial = ( oldMaterial == nullptr ) || + ( newMaterial->compare( oldMaterial ) != 0 ); + + updateMaterial |= state.isCachedMaterialDataDirty(); + + if ( updateMaterial ) + { + const auto* const material = static_cast< const Material* >( newMaterial ); + + p->setUniformValue( id.color, material->m_color ); + p->setUniformValue( id.arc, material->m_arc ); + p->setUniformValue( id.spreadRadius, material->m_spreadRadius ); + p->setUniformValue( id.blurRadius, material->m_blurRadius ); + } + } + + private: + Uniforms id; + }; +} + +#endif + +namespace +{ + 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* const other ) const + { + auto material = static_cast< const Material* >( other ); + + if ( ( material->m_color == m_color ) + && ( material->m_arc == m_arc ) + && qFuzzyCompare( material->m_spreadRadius, m_spreadRadius ) + && qFuzzyCompare( material->m_blurRadius, m_blurRadius ) ) + { + return 0; + } + + return QSGMaterial::compare( other ); + } +} + +class QskArcShadowNodePrivate final : public QSGGeometryNodePrivate +{ + public: + QskArcShadowNodePrivate() + : geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 ) + { + } + + QSGGeometry geometry; + Material material; + QRectF rect; +}; + +QskArcShadowNode::QskArcShadowNode() + : QSGGeometryNode( *new QskArcShadowNodePrivate ) +{ + Q_D( QskArcShadowNode ); + + setGeometry( &d->geometry ); + setMaterial( &d->material ); + + d->geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip ); + d->material.setFlag( QSGMaterial::Blending ); +} + +QskArcShadowNode::~QskArcShadowNode() = default; + +void QskArcShadowNode::setShadowData( + const QRectF& rect, qreal spreadRadius, qreal blurRadius, + qreal startAngle, qreal spanAngle, const QColor& color ) +{ + if ( qFuzzyIsNull( spanAngle ) || color.alpha() == 0 ) + { + setBoundingRectangle( {} ); + return; + } + + Q_D( QskArcShadowNode ); + + if ( d->rect != rect ) + { + setBoundingRectangle( rect ); // bounding rectangle includig spread/blur + } + + const auto size = qMin( rect.width(), rect.height() ); + + { +#if 1 + const auto a = color.alphaF(); + const QVector4D c( color.redF() * a, color.greenF() * a, color.blueF() * a, a ); +#else + const QVector4D c( color.redF(), color.greenF(), color.blueF(), color.alphaF() ); +#endif + + if ( d->material.m_color != c ) + { + d->material.m_color = c; + markDirty( QSGNode::DirtyMaterial ); + } + } + + { + const float r = spreadRadius / size; + + if ( d->material.m_spreadRadius != r ) + { + d->material.m_spreadRadius = r; + markDirty( QSGNode::DirtyMaterial ); + } + } + + { + const float r = blurRadius / size; + + if ( d->material.m_blurRadius != r ) + { + d->material.m_blurRadius = r; + markDirty( QSGNode::DirtyMaterial ); + } + } + + { + QVector4D arc( 0.0, 0.0, 1.0, 0.0 ); + + { + const auto a1 = qDegreesToRadians( startAngle + 0.5 * spanAngle ); + const auto a2 = qDegreesToRadians( 0.5 * qAbs( spanAngle ) ); + + arc = QVector4D( ::cos( a1 ), ::sin( a1 ), ::cos( a2 ), ::sin( a2 ) ); + } + + if ( d->material.m_arc != arc ) + { + d->material.m_arc = arc; + markDirty( QSGNode::DirtyMaterial ); + } + } +} + +void QskArcShadowNode::setBoundingRectangle( const QRectF& rect ) +{ + Q_D( QskArcShadowNode ); + + if ( d->rect == rect ) + return; + + d->rect = rect; + + QSGGeometry::updateTexturedRectGeometry( + &d->geometry, d->rect, { -0.5, -0.5, 1.0, 1.0 } ); + d->geometry.markVertexDataDirty(); + + markDirty( QSGNode::DirtyGeometry ); +} diff --git a/src/nodes/QskArcShadowNode.h b/src/nodes/QskArcShadowNode.h new file mode 100644 index 000000000..5d76b9bf8 --- /dev/null +++ b/src/nodes/QskArcShadowNode.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_ARC_SHADOW_NODE_H +#define QSK_ARC_SHADOW_NODE_H + +#include "QskGlobal.h" +#include + +class QskArcMetrics; +class QskShadowMetrics; + +class QskArcShadowNodePrivate; + +class QskArcShadowNode : public QSGGeometryNode +{ + public: + QskArcShadowNode(); + ~QskArcShadowNode() override; + + void setShadowData( const QRectF&, qreal spreadRadius, qreal blurRadius, + qreal startAngle, qreal spanAngle, const QColor& ); + + private: + void setBoundingRectangle( const QRectF& ); + + Q_DECLARE_PRIVATE( QskArcShadowNode ) +}; + +#endif diff --git a/src/nodes/QskBoxShadowNode.cpp b/src/nodes/QskBoxShadowNode.cpp index d94d8ad36..6f730ceb7 100644 --- a/src/nodes/QskBoxShadowNode.cpp +++ b/src/nodes/QskBoxShadowNode.cpp @@ -40,7 +40,7 @@ namespace int compare( const QSGMaterial* other ) const override; - QVector2D m_aspect = QVector2D{ 1, 1 }; + QVector2D m_aspectRatio = QVector2D{ 1, 1 }; QVector4D m_radius = QVector4D{ 0, 0, 0, 0 }; QVector4D m_color = QVector4D{ 0, 0, 0, 1 }; float m_blurExtent = 0.0; @@ -91,9 +91,9 @@ namespace changed = true; } - if ( matOld == nullptr || matNew->m_aspect != matOld->m_aspect ) + if ( matOld == nullptr || matNew->m_aspectRatio != matOld->m_aspectRatio ) { - memcpy( data + 96, &matNew->m_aspect, 8 ); + memcpy( data + 96, &matNew->m_aspectRatio, 8 ); changed = true; } @@ -146,7 +146,7 @@ namespace auto p = program(); m_matrixId = p->uniformLocation( "matrix" ); - m_aspectId = p->uniformLocation( "aspect" ); + m_aspectRatioId = p->uniformLocation( "aspectRatio" ); m_opacityId = p->uniformLocation( "opacity" ); m_blurExtentId = p->uniformLocation( "blurExtent" ); m_radiusId = p->uniformLocation( "radius" ); @@ -173,7 +173,7 @@ namespace { auto material = static_cast< const Material* >( newMaterial ); - p->setUniformValue( m_aspectId, material->m_aspect ); + p->setUniformValue( m_aspectRatioId, material->m_aspectRatio ); p->setUniformValue( m_blurExtentId, material->m_blurExtent); p->setUniformValue( m_radiusId, material->m_radius ); p->setUniformValue( m_colorId, material->m_color ); @@ -183,7 +183,7 @@ namespace private: int m_matrixId = -1; int m_opacityId = -1; - int m_aspectId = -1; + int m_aspectRatioId = -1; int m_blurExtentId = -1; int m_radiusId = -1; int m_colorId = -1; @@ -231,7 +231,7 @@ 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 ) + && ( material->m_aspectRatio == m_aspectRatio ) && qFuzzyCompare(material->m_blurExtent, m_blurExtent) && qFuzzyCompare(material->m_radius, m_radius) ) { @@ -284,16 +284,16 @@ void QskBoxShadowNode::setShadowData( d->geometry.markVertexDataDirty(); markDirty( QSGNode::DirtyGeometry ); - QVector2D aspect( 1.0, 1.0 ); + QVector2D aspectRatio( 1.0, 1.0 ); if ( rect.width() >= rect.height() ) - aspect.setX( rect.width() / rect.height() ); + aspectRatio.setX( rect.width() / rect.height() ); else - aspect.setY( rect.height() / rect.width() ); + aspectRatio.setY( rect.height() / rect.width() ); - if ( d->material.m_aspect != aspect ) + if ( d->material.m_aspectRatio != aspectRatio ) { - d->material.m_aspect = aspect; + d->material.m_aspectRatio = aspectRatio; markDirty( QSGNode::DirtyMaterial ); } } diff --git a/src/nodes/shaders.qrc b/src/nodes/shaders.qrc index 82a427483..7d2d15a42 100644 --- a/src/nodes/shaders.qrc +++ b/src/nodes/shaders.qrc @@ -2,6 +2,11 @@ + shaders/arcshadow.frag + shaders/arcshadow.vert + shaders/arcshadow.frag.qsb + shaders/arcshadow.vert.qsb + shaders/boxshadow.vert.qsb shaders/boxshadow.frag.qsb shaders/boxshadow.vert diff --git a/src/nodes/shaders/arcshadow-vulkan.frag b/src/nodes/shaders/arcshadow-vulkan.frag new file mode 100644 index 000000000..49646de34 --- /dev/null +++ b/src/nodes/shaders/arcshadow-vulkan.frag @@ -0,0 +1,46 @@ +#version 440 + +layout( location = 0 ) in vec2 coord; +layout( location = 0 ) out vec4 fragColor; + +layout( std140, binding = 0 ) uniform buf +{ + mat4 matrix; + vec4 color; + + /* + arc.xy: cos/sin of the angle of the midpoint + arc.zw: cos/sin of the angle between midpoint/endpoint + */ + vec4 arc; + + float spreadRadius; + float blurRadius; + + float opacity; +} ubuf; + +mat2 rotation( vec2 v ) { return mat2( v.x, -v.y, v.y, v.x ); } + +void main() +{ + float radius = 0.5 - ubuf.blurRadius - ubuf.spreadRadius; + + float dist = abs( length( coord ) - radius ) - ubuf.spreadRadius; + + if ( ( ubuf.arc.z ) < 1.0 && ( dist < 1.0 ) ) + { + vec2 v = coord * rotation( ubuf.arc.xy ); // x-axial symmetric + v.y = abs( v.y ); + + v *= rotation ( ubuf.arc.wz ); // end point to 90° + if ( v.x < 0.0 ) + { + v.y = max( 0.0, abs( v.y - radius ) - ubuf.spreadRadius ); + dist = max( dist, length( v ) ); + } + } + + float a = 1.0 - smoothstep( 0.0, ubuf.blurRadius, dist ); + fragColor = ubuf.color * a * ubuf.opacity; +} diff --git a/src/nodes/shaders/arcshadow-vulkan.vert b/src/nodes/shaders/arcshadow-vulkan.vert new file mode 100644 index 000000000..4899db18d --- /dev/null +++ b/src/nodes/shaders/arcshadow-vulkan.vert @@ -0,0 +1,21 @@ +#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 arc; + float spreadRadius; + float blurRadius; + float opacity; +} ubuf; + +void main() +{ + coord = in_coord; + gl_Position = ubuf.matrix * in_vertex; +} diff --git a/src/nodes/shaders/arcshadow.frag b/src/nodes/shaders/arcshadow.frag new file mode 100644 index 000000000..738b0ed49 --- /dev/null +++ b/src/nodes/shaders/arcshadow.frag @@ -0,0 +1,37 @@ +varying lowp vec2 coord; + +uniform lowp vec4 color; +uniform lowp float spreadRadius; +uniform lowp float blurRadius; +uniform lowp float opacity; + +/* + arc.xy: cos/sin of the angle of the midpoint + arc.zw: cos/sin of the angle between midpoint/endpoint + */ +uniform lowp vec4 arc; + +mat2 rotation( vec2 v ) { return mat2( v.x, -v.y, v.y, v.x ); } + +void main() +{ + float radius = 0.5 - blurRadius - spreadRadius; + + float dist = abs( length( coord ) - radius ) - spreadRadius; + + if ( ( arc.z < 1.0 ) && ( dist < 1.0 ) ) + { + vec2 v = coord * rotation( arc.xy ); // x-axial symmetric + v.y = abs( v.y ); + + v *= rotation( arc.wz ); // end point at 90° + if ( v.x < 0.0 ) + { + v.y = max( 0.0, abs( v.y - radius ) - spreadRadius ); + dist = max( dist, length( v ) ); + } + } + + float a = 1.0 - smoothstep( 0.0, blurRadius, dist ); + gl_FragColor = color * a * opacity; +} diff --git a/src/nodes/shaders/arcshadow.frag.qsb b/src/nodes/shaders/arcshadow.frag.qsb new file mode 100644 index 0000000000000000000000000000000000000000..1c90703303dc33dbd0af723f231835b235812372 GIT binary patch literal 2282 zcmVPk-Q+D~di zY>OsH3h@Gbo98;?nt=O=2tacR8hz0Q`Y?@MWqdE02kka@;3^;H*92&dfnBq$?ZtLd zB%%R~9TO%ZZ(XO)GtXN9%8R7PtSZB_(|f2)tN>drBT{xc*$wYn)1U^ zy;=6;rNB$wx|5{ky1#vy;fWuV&*4X*cG8xxShn&gSnig)wSm&Bmu;t&`xU@D;Nlql&nq5R*uZaUfPU9 zX~b;(V7ChGyqswjI=Q^;LY=$>JeLEvEDIwIypYX=ezHw`;4s7k&R0F4wzl%x1vgY# zoR&@a1P1u5czT+QPnkx%m*vA8bN;a3VLp~@BOw)iG#qP{=I+v^=}qr`wrjS};sVHiT1zaJq07QRYI$ zP1421z->c9ih1MF{&UGJ;YB&gG$D|el%H0PvF}>hr%tE~k}&6BCJCY_ttF|~(600? zjl8l$x?pJ)vTB9Zq?lFB!mPVF_)ti<_*u1ptf~QQjcTz9{Zlu`TISa!y|Qt!%SDi^ zf^Asn+r@6_MLSO5ehK!vy$mfnx}kv#SiT=sDv6icrDCq9pD9M|Y%kyZ5I)F#AJ+os z(o8%%ecTrYxwA>_=k2aV#!YiL!1^GkJDh28ycaI@fUL7-opfXE=K7|y5=Tkm+zcDN zz1XzWMS17_&sJ{VUcX-KX~SIjb~A14-N_f_#-?+}jjLWtDh8XZsonp%t+pb+tZX~D zuwD*c_W@?Bb=vrp>_nsvLc=jC-OpSJfo zgS~H<8EAiyh`m~1W&a*X-LJBD`*WV${+_b&RR%g=CEvd?dRpH=+j9omo|C=vSk_>v zsGn$ip#G%!wTEZ3a&;9h^PvJ2xbcOSx(0?A)1r|gG!sX9x;X0+tPFb<>|);@Lz~pA z%URpD{x&)?HHmM}7HlqlN9fDY-SK_;FuWY&_v)>UTLpNNEzBB1bHW!M}Qmo-=TSWkH(DNi!={L@4Li% zk;yKS>==z3KbMC1d5LhNZ<*vTk)P)Yy9T4E<0|R6Ol!jExkh7u1wH8V3Sn(Kd1S_SaDr`#Qa>Qn*5mX+aNKi zzBTqS**HWoe@J8Rf-dYMYeFA)ApR%7Q1%yObB$zf5{CA1ZLJHv9*?p3HwZU*y2J9c z!DK&SvZ(tL;x(~-IwZEw2sg3)k}$kYUqxM;G-hJ^oMPK#b9tBSn^?af>~j|D7tG%+ z;y=n_{T1OR*A8KCQeIt_R~)+sw@Z1w$8>KGna2|0hQ{A1UK1Yil-XQY*j#%etBI-@ ztce=oMxRgeHKlJ-VPBFyn_}{r&-eTCcc1u;emsgi&*nQIe&cH>vf2-r&4}5o6Q8M3 z9Q!BCotZ}-ux{g!wsX>@ovmLV8 z7TKD8K)A8_Q0SigN07ns-w@A3=KF6+&n}aDM7WWAOtO#2mmR|X4G~;~`vR?fbA*ZS z3-16Q{ze?8`T8Nt=gWli_5BLrhUYl(@OAns;g5(uL70(wZHUZC!VS-lhS+|c@HMK> zACo^P7Wt5)?1i0<%?&lPH|6V*$yKNZh z*@Y7@xCejI_WPNfJpR9r9o0nad+4aA3Pzv$yfL%!TuvLG#W~~iIbr;-P8aoQBCpam ztJ23=mCk)ntF-0D9sJV`FV%yxJSfZWU0GJ^&IeGL*WJ{;TiklO+APyI*5+Tb+AJ0= z2(siWs^(W~4ejaD0PKh9us>=Z)bT+bAJp;lsbg~(#r~gzscHScPsG3<^?Jwu1J}Sl EP`UJ}DgXcg literal 0 HcmV?d00001 diff --git a/src/nodes/shaders/arcshadow.vert b/src/nodes/shaders/arcshadow.vert new file mode 100644 index 000000000..018500396 --- /dev/null +++ b/src/nodes/shaders/arcshadow.vert @@ -0,0 +1,12 @@ +uniform highp mat4 matrix; + +attribute highp vec4 in_vertex; +attribute mediump vec2 in_coord; + +varying mediump vec2 coord; + +void main() +{ + coord = in_coord; + gl_Position = matrix * in_vertex; +} diff --git a/src/nodes/shaders/arcshadow.vert.qsb b/src/nodes/shaders/arcshadow.vert.qsb new file mode 100644 index 0000000000000000000000000000000000000000..ae08a617e90ce04b542051094ed46eb879ef228c GIT binary patch literal 1585 zcmV-12G02a03r-{ob6iOZWBio9@|MsHVGtYAkYF`NSfLqbxjnYN(chcsvsc|B^9cK zqGe;R!?yOW*&j$ixoq!y(!m1&Y5q{|IX|T z2qA`rx=L_Q30HW+5_RFjUmzO5E5cp)hc1!6W(faMIDn4exeweS?CLwh5-$L0k$fBn z^5H(!X9V^cIg9$qNA!r;6|rbSYZQKUyTwo=a8HP~u)&f5d_b$msqZesP3eX*pe0RE z4&LS6{2BqN0l*b(vmfld2t@~g4!|2?OFmsNH6$mVk$~Ja3m&xq81xv_=r`yzSl$76 z9pI5TAo%ls@T0B?8Z?oxiuSzg)mw4HF>kk>$ZlC-)M&Z8cZ`G|y6wi7_^3X=V;FJh zdV8j4x1F$K*Bw)iS~rX^3gUWX?#4~yjbXyoZ25Myy1#0+?I>{f*BR5S`z=36aqOVZ zXfx~tj@{U@8*UtO{%$J{@?0M*aifEE<1jI#ZM$C0^5ck`vjUp^pkY3J8i!6$Zuxbu zR@vD}S+du%HvQ0zT;Bs+hnfh=Nq4=Jucqr+FP$KA_F>DvnM=DhCW&eGTBQI)L)NS2{&Qs9&fVdL_xw(6hQK zBpH%5$nBmRMo?F~HEnC)zp~o)4}Orm@o1VwrmdL};2-^FGjyVIy;e!RYZ55anZd30 zz(JZbs2d!mKs@;w^vygvDTyq$dXPs`spO!qE2?^+e(lJu_n1i5Q(fIUN;8vWr{%EJ z@{Uvq(VMfq`EcurbwBXK(0b@~(vu&bpVrLpzWM(CM0(vDl@uK&xtL@WR0mC3uQ-r!sYOg&RW zTie@>@&@nCOuR|5awz_$CuXK$tUA<0*$tXv^l(58_a&h~oRe7vQq`TqYWJ8wv@E2R z9P+sbSBGDdZTABF1&A}k zkZt@V*E+_8+Rl6g_hq;jPzE5zh!#YT6OD2nz(#PI`t(*v^9sb{xFYdNQdX(UdjN9h zX#6nYH9gPdY92T*H%OXSAlzNXD-v&$@k+#d#&|=-YcSq0@t%{NS|0j;0e-Ktcp!a+ z(U&vvS|IwAjBQcMxdJjvB=a1!aBFG8JqLKijZmKn^eEYl{B@$oh==_K`LFv87I&04 zN%GLov+z7ky70P2^clim1bT|_XQbUKZ(7C_>6{_`)1-4osJbbUj#<)CARV)kudeez zpCg$=Qpc!_ujXl8`bK@{DIRmA59tdmMjv-$spw0jdy?>%L{hWZe}!zFBzj)xLjZ+G zdV$%GFa1&xy6v-YLaen~^Yifh?J3%?R1HEHJ-vb2t@d^2Mmhk6f zUKD?W^7$$G^9zibq*z}hKFUG=u2N3UlAf!CLm6oIXXN8OpwOQ(!!I&ih5CL1xkxY3 z*a{oF%*I|LeanRX8>0A?S`zep#!mvEqxk#DNx&eT1oZmm=BQi8=DZ*?LVkP$ihqA+ zA+O%*q(P*=f{yt~!~6XT;^zZ6ul{jzJ}^M%1Mm49;6vZ$57NH44rnzuoD;m~0<)I&g9_@c&K*PEG;_?<8Q* jckX?5(wTo(*Qc-Qe>;fWZadeX`K~^)KR5ngN?pPF4kaH6 literal 0 HcmV?d00001 diff --git a/src/nodes/shaders/arcshadow2qsb.sh b/src/nodes/shaders/arcshadow2qsb.sh new file mode 100755 index 000000000..d78eed3bf --- /dev/null +++ b/src/nodes/shaders/arcshadow2qsb.sh @@ -0,0 +1,10 @@ +#! /bin/sh + +function qsbcompile { + qsbfile=`echo $1 | sed 's/-vulkan//'` + qsb --glsl 100es,120,150 --hlsl 50 --msl 12 -b -o ${qsbfile}.qsb $1 + # qsb --qt6 -b -o ${qsbfile}.qsb $1 +} + +qsbcompile arcshadow-vulkan.vert +qsbcompile arcshadow-vulkan.frag diff --git a/src/nodes/shaders/boxshadow-vulkan.frag b/src/nodes/shaders/boxshadow-vulkan.frag index a5d5451e9..58d79062b 100644 --- a/src/nodes/shaders/boxshadow-vulkan.frag +++ b/src/nodes/shaders/boxshadow-vulkan.frag @@ -8,7 +8,7 @@ layout( std140, binding = 0 ) uniform buf mat4 matrix; vec4 color; vec4 radius; - vec2 aspect; + vec2 aspectRatio; float blurExtent; float opacity; } ubuf; @@ -25,25 +25,21 @@ 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 e2 = 0.5 * ubuf.blurExtent; - float r = 2.0 * effectiveRadius( ubuf.radius, coord ); + const float minRadius = 0.05; + float f = minRadius / max( r, minRadius ); - float f = minRadius / max( r, minRadius ); + r += e2 * f; - r += e2 * f; + vec2 d = r + ubuf.blurExtent - ubuf.aspectRatio * ( 1.0 - abs( 2.0 * coord ) ); + float l = min( max(d.x, d.y), 0.0) + length( max(d, 0.0) ); - 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 shadow = l - r; - - float v = smoothstep( -e2, e2, shadow ); - col = mix( ubuf.color, vec4(0.0), v ) * ubuf.opacity; - } + float v = smoothstep( -e2, e2, shadow ); + col = mix( ubuf.color, vec4(0.0), v ) * ubuf.opacity; fragColor = col; } diff --git a/src/nodes/shaders/boxshadow-vulkan.vert b/src/nodes/shaders/boxshadow-vulkan.vert index 3a3080602..0fe63bd99 100644 --- a/src/nodes/shaders/boxshadow-vulkan.vert +++ b/src/nodes/shaders/boxshadow-vulkan.vert @@ -10,7 +10,7 @@ layout( std140, binding = 0 ) uniform buf mat4 matrix; vec4 color; vec4 radius; - vec2 aspect; + vec2 aspectRatio; float blurExtent; float opacity; } ubuf; diff --git a/src/nodes/shaders/boxshadow.frag b/src/nodes/shaders/boxshadow.frag index b24ff1856..61b857f7f 100644 --- a/src/nodes/shaders/boxshadow.frag +++ b/src/nodes/shaders/boxshadow.frag @@ -2,7 +2,7 @@ uniform lowp float opacity; uniform lowp float blurExtent; uniform lowp vec4 radius; uniform lowp vec4 color; -uniform lowp vec2 aspect; +uniform lowp vec2 aspectRatio; varying lowp vec2 coord; @@ -18,25 +18,19 @@ void main() { lowp vec4 col = vec4(0.0); - if ( opacity > 0.0 ) - { - const lowp float minRadius = 0.05; + lowp float e2 = 0.5 * blurExtent; + lowp float r = 2.0 * effectiveRadius( radius, coord ); - lowp float e2 = 0.5 * blurExtent; - lowp float r = 2.0 * effectiveRadius( radius, coord ); + const lowp float minRadius = 0.05; + r += e2 * ( minRadius / max( r, minRadius ) ); - lowp float f = minRadius / max( r, minRadius ); + lowp vec2 d = r + blurExtent - aspectRatio * ( 1.0 - abs( 2.0 * coord ) ); + lowp float l = min( max(d.x, d.y), 0.0) + length( max(d, 0.0) ); - r += e2 * f; + lowp float shadow = l - r; - lowp vec2 d = r + blurExtent - aspect * ( 1.0 - abs( 2.0 * coord ) ); - lowp float l = min( max(d.x, d.y), 0.0) + length( max(d, 0.0) ); - - lowp float shadow = l - r; - - lowp float v = smoothstep( -e2, e2, shadow ); - col = mix( color, vec4(0.0), v ) * opacity; - } + lowp float v = smoothstep( -e2, e2, shadow ); + col = mix( color, vec4(0.0), v ) * opacity; gl_FragColor = col; } diff --git a/src/nodes/shaders/boxshadow.frag.qsb b/src/nodes/shaders/boxshadow.frag.qsb index 8ecfc828aa472382eb72816fe916e075d05238ff..3792962e6c2f61324ba37ef9878831e4e61edc89 100644 GIT binary patch literal 2606 zcmV+}3eoid04rs9ob6hBcNURmUiV$rCqVRvgM?1Qv#(xNeP_8IeZm91AGephJSgS17+skx!PGtHV!Q%oa6Ob zY3DbOJ9qBv%wDa95JN(UK{%g+Gbbt{guh5sff|5Qd`gGN9w@z6cp&MBnm7+Sb)~0m zZKgFWmP89Qh1dz-=DNwGhT$9)4X~VmMPIamewuh^ncOqxLc7f!ILq1m7*!ru!D>sy zBs{;7@O}`D!8I4`Ct^W4e(-w2z4J{2D?od zp#mc$VvWS>8;Ngr43p9*gMK^KjGS7-k(Ig=)MV9nYC#w$ent9l5xG@)aQtS&k7GZm zjW?q(36r&^8z0Q&#{8gCZ&h7+s^KP1-HwxL-CsJ*@YruukKspg`E)MVLK8A@8gATl zDy~#ov$Vs)AB0b|b4ERsyc)s9*+GE%A zV0!+FyP&3SCCicPRAG=HPRP~6DlC3M_VUVyWi#}HBu_5-p0pHDY|GQKR4nBcteI(; z?Bk``4wUMwahLoNx{;f-q9FB5b2=7#W-vMVpUhx# zvg5_w$DIMwUEOR3#wG>lEwvWfYd^43|EtAzK~{@vc{PtbI8b+kTC&VV3dX-ukJ)(HsfMdy zyADq9QYu#fj2mH?EXRr4w8q_XLE@=3$cWC7hTqmxRAsQhbEZSAhx zReRe_1JjnbniaQ_X*7!FsSLnpX)>+A_rj=wE~xMTwBkf-*d3K+x+^xQ_8o7ax-0SR zYW^fw^OexAs=8~LB{Jy+#_;m73$4=Mu*~X|=oHy6u)==E+NvC{>YzMcT~!LKs%~CV zv6yaJMyY@*t6xz0?BoGmZd5vJb^A4_oEMzLxm8*;wNuy1K}<5*ft1+;{+}!QK|qz8 z8A#Ha5B^2gQpqG_6t3D0=MEI(&XYF|ZR?r{I^e=Pq36YJVpTG^N`h(@U2>Cs6x+70`<6V=>=O!RLOY;WY7 zX8~#VbP7AuD!eWB3OiG3z5mN@vDG>JZ~6r;xSeSlnJ0AgxY&lHU)%7ga@bpVK({x2 zK;Ni$c%OIk@V44Lye&PNcbW$aK_22|`iI@sKPGfId%K6X<@VwA_77U5|3deuyHV3h z3vVIK2WTJa+jI{*(>;0~x*^?qOOJk7>8WSZ>^I@sB&8139A{;=bZHiApwD1hHB^Ka z;z(wnz^X30d$I=Bc_+lp!f(<}IQXY@(=b(fLN@}iwdZ>P+@`BhdCS?}7i{kfw)X|w z`-06YJ1c~Oem$XM^wf@lu@S6~Ik8jxn$SJ4bHIxEv=~<3m#$p9QjC*o5f)3ohuERy zkhfcms22%%nlavh^O3+8COZ@k1Bln*>NMFOQuI)V9;0uLjR^h1#b8g7+*yVV5H`=S z9faLx*dSrc3>zX0-=16oEo1KzNaGj>$qz%n%xIk7i;RB6=x4#ofRf*#e8KDeaD^{i zB%IHKJkHI$fRXUIljb`@{9VK!AbyT`yOiA_^`Z;;sE54gK;{{;kH=A>_YjRX_L7ZZ z;twl5ee8pg_A|W~DBgxXM!p#OIK{aD7SZMm+2W@es|b}yZFs6`rR)2KGCPa+mnt3vVmh=B^>3i5Islt*mr1skvC8D zNf-&oS`b+0bWG-%57#J%7D(?BVaDeh6xUH09qF62z83K?Up^vRZxVfzY+WbJ*!mu= znW5jJH88&1BAK_C%=c;h4@hQ_uv^UEMJ8{Pyjh3aeb&Jt+}K!|&nAl(NfgJaz%zPaCjLOJ)LNbmQL2sieBDsp`nzk@vT4p6S)*aw*Huaa$kAAF5)WBcob8QYTCM&3(8KaZj9mzeFB zY3|(bgM?!YUnKf(peIRxjOl-a^to?`2siqNy7VQJJxsCvC*X&PZ!!D%K65`pxS9J= z!pz)@Z0^V#7y5U4v^~yjm&o^H%=QG~=zD=^^u0*>Wu`w#`p2366yZjHs!PAfWTz>Q zaPHH@$DH_-@>OJiU}=laG5E*y2bS`a`UA`Mo7U}LRJMOn+5Sc4b9&R-_3xDCA5`=| Qx{98+v047V0QH^A6f>|mNdN!< literal 2656 zcmV-m3ZL}=04+Lrob6hTb{o|ZzBsX+2)855zs3E$=7q~?4#pp*xg^-S@iqoW1mwL+9 zW?Ca+S+qz~h+XulpPL41gzhoXAj>gX^hBHJhao#<;P&VT<+ka-DN}4-W76X?S#603 z;DwFB4uP7&CHpY~azi>k;MzxXsgu=EoF$KAQu3t|&$*`KlDxi6J~wHU5;+u$HNfi| z!8f}`;9$PX8l5REw<;AkwCKY+X@zdpi()rSFXu9;TPcgKFjy@%oVSC}s?-A~F0>0) zi@?N-L$6IbO{eruP^m<2oG#@uvrDX2Gh2PW3cT zcb4H{i@dzDaN+W`;^{DmqT&U=*@_WX(+rJy_3ZW2mo8mClT(8YP`=cP6WYdjWZ}xS z;#DWCx-m?sskyYcrPy0>FU#nrp~$iJvf7DaGw}RaFSu8+(u!lZt$8bF=PDT~P~vXb zipO%Z9hRZB)}z&{$rtHabIJv~-LbXPZ`=! zuH%KN+|-HO)Xelu{@989iOD=o;i%Pc+UYR+WkADtXdRie(iDZmRwX%R-YV0eX@Vp} zlc8{169_X3(_t$;sTP7H&T^DioBXhxZzj_>Azrx#Eh)QPw%b{&Y_DaqYN=?%y6act znv!Pq68Bq)YEC&=B~x`8HB3rZNDwuGAg)n)Z>A^QeAePyX&J^;BGuinneJBaY&WyA z){6Yh=rloYnY*o9mU!{&vz)&DrOc9f+*cnhDydbs=<%~oauvWiQ)C-iW$X&Y7%-Sp z4J4sJCdW2iHmbO>8+#3`r?><2nCQr5e9|@i=J<*mMqc1slet`~8M-A;QZ=tyYpMmA z?PGhq&vfCZz+&nR-fybcDtA`glHBgvJxQB;kQjMOrJ~v7lG|BvJFCYnqvd;*AZ*C* z0=%}wT5-ZP&#x+@2>AxBrQ--S776d`Dm_hQi#?^M9RFW-l&#I+{`8ZcR-!YDjPYZd z-R*58c26VOypNzh*n`@L9La1VcCv}61lm#yxfdN|s}1DK`-hxJS%oy;=^#c_GP-@( z-S#1|)I&1;4dg5JkN)-{E$0TB`9>Q^!)vQap?`D|3Xdxp-9YRC4WwExo}(gs#)+N9 z+>+5n5=HlJ_kS|O$Gb&$D)-wRB>GJ^m(Dbtg&GUQOpzj*=V`ODW;&(`2`1uKX;x}^^-A@vp=QaYr zEc&|(^BskJx9GmfV|fa)-O}!`d=JWU)??Y@gxLf8d>sM37c|>=6gEa6ACY?M+D9Wj zVdy=Dcx(D7e9`nV#5qeA+2%>uGVlF_oyC|tWqfwY7;B!M&j@bzaSr1soTBH!<2gQ$ zIcndYM?MTg{{>*pIliQ(_`JqnfInLPs*<15@=HeC7ckat_`~#T;IaG)u%m{(MY{j? z*Nb!7o`+a5{%zoQ8~BDC{&vT|PYwHjfbJ;9XZkL9(=_WL(S1eCynhmB7+B7Y8AF%X z|9pae#h@8~*`PVEt|jnqCFJFVd?i7@pP)YiJx|`wAa7nEk9pl*#9H%u&LK9Z!T$?k zI6u#T$NBXSvT+V`|2N@Tc9!mQh{IXK_77qEf?@k*@INFB(-)B|FT=m{;IR!}=c}-B z2{w2huXp%6Wb9stjMw)KvgCM zScfY3+GY)URp{}ac?Wu)5#Kuan)VUz&q#;q0K8XayhbFiiFoaVd;!>>2(=ISz5`we zeiJcaUW9Q&LpO%cHAA-reuTJ`!Q=VxK3ElM@9Z_=&<0;))_{4+z}y61um3G${o9ah z*-s%m2;AdFtkz*$&*5jHTen%CdG8vw*MS*B{@#Y{Md0+>y@zpcW8N#^Y5(sCRU# zNTtR-zf^CPUF*4q8$0!46qoDX^1Q*1yhiyb|FLWHR3_PkZ_) z$v5@nAtTSPd%kNGi%v|_U2es0v6xOf^;KsrDk@efo?9GWeq;q*2zNkl-9XL$wIlL&r2*VW!3UJzT7{DWMv?LI{YV7G}HM)q%HD2 zXWd#)?khebA&Gm~!3G>O>g!>B2aP=6z7LJ8;zaSuliyG~Gmaan$E~(BppB-cqp@jU zgY(qgy3^RO#~BcPcJO}mIwScy#OD1jNSyGI?atU-fjZK|?QdA-zfkXD6Q^bM0UvdG OxxYvD%Krzc77pV!&2d2h diff --git a/src/nodes/shaders/boxshadow.vert.qsb b/src/nodes/shaders/boxshadow.vert.qsb index d9831605a22608de23815ce59e348623f0add7e8..2e1e841bb5032bd922c2ab832e10089227db998c 100644 GIT binary patch literal 1576 zcmV+@2G{uj03mXCob6g|Pa8)NUTj{Ew*&&TB~30NO>BrX)jY`=!6AKcPRSU#fOych0wWwy98yf8jObFI~q46)F8ZLtj=`s#Df^n>rs+zNVpr(KsaD?7es&? zvRHn`0HTAR7TEO(yxk2v3s4_iGeLjAcDO?pSP?OsZ;8R3@ zL^j)=3DDaB3kFyS*eSv7Zt(M-F`8VZZ+QEDSvWR5-*O#wxmZ*bKkz~$P!GbI@?KHl zsp~-rKRl~h=8R+0D5-{PyPiaQdesX37Gp)#{f21-J9=Qbf?Km)9rW6vx7iF#Cy=>r zLpQA8w5*(!6(w}6n(Nik1vP{ZU>)n;spT9B&4%lG)v}@o;L<@Dn1X9LS|>pX1rT6h zHf4!0tGx|0m|}Wp!nLXprsd@F6gXF>RwT{HJ+!rL*S7*pScUsn5Xn&&Wm73=;T?cm z<^U?oP9SbY!SzJ@w60_Es%5GRmSfmq)l|Q(n}Kd?eo(cogLNh5`&PaBC4Ll+)**#H zX3Np*rVp7lRX(fSVR3mLO3mZ~3#Pop#E}=7v;NC6lP?%@QFFsU_J|f)-P;R&)63be z;S}@x`w3^{h1lC`&=5gw+ASv$ZoEz~v9%|1DGTwIN}!hWkqJ`K3P6lKsr4C5Bb&s0DRUUL^Pgn{o*2x_*T^SXTmL@3h|~aB=;o>&)=Jc)b{ku zAoLuZ8126SZkf)8-)Q&Y8R5id#A>ge5tu9ae1P<)4hF$VoCv_`?W2IvX-zB9U(IF~ zhH$7rg;^rOO{hA!WTQ|Z@%x)syRQmxMife`MNvVrkpec!6h6i?CbBWYL>a|WHxKVU z)ByhAm#E48V^eHJo)qlc14E8_b9~u2^`!j6 zM~Hp~h&i4w5$hD;F~(1cU!irnP4WE-bCCX=FtHNzwcAb&w#>s z9!mHJ67CVneg?fr=VzFgqZsL|25rouV?qg$)_W{@+A`9w|UKwdUdxKan4C?_f4 zYCciIIZ!GyDfAN=Ex>W{Nn;D|+R;>$+Mp+SQKz6(f?1=(ou!-*wW?N<8P}Vn9;v!S z#dvr7<<4vEx##-6_R?u2?^E)XXHETX^ZVypTRSg`oo_oaU^#J@k}Yh7L8J4Pt+V>% zb!|=EeJv&8EULNap?2ZITMzAAE4;_@X3O(x+U~a~?rj-UqstnMBL`YpsmRjQ-78LR z8%n+eNZ|=a2hYTGmlFacb5b|F#CB@KMt)0<(v>f1bs(d^R{QtcU-P>+RZszyvw!6pL?l`9S*CL~yUYX`RHG`iJfRYc1H00z$Z9S4p zSGBFb+;f7lxF^Ru@lSG3t`hfRJ^2V9pVyOL_v0}w_v6?7_vQ89z1|=HOTUVLUuInQ ztG(5)%7Vld`*Qo(PB(`b@btrPbT8gg^h{qIyP1SZyW>M_pINduyXx)p<@aW(e-@1z aVDWznSX=+rCQtoc=DG5=`TqbWmBfNrpA;Mb literal 1559 zcmV+y2I%RM|3>IH3$Szi-bf(DpV;- zjpOqLw?6yuBMG2LRi%D_{?o71kI=8vf2ww7clJEC??6GN3N#z}ygT#Td9HmkNrVvN zLXAKt5at zhU`F|QL<>5d_+%(b&-k=%nrg`&wC6t0oSzX3L7kmzz4K?igNILBVg!^4 zDBzj{a4Inc;B^jMP(YQi0`LY0DqNPvBDVgjjHdLKpj$PSaX4>w;yK!67X4O^)z5vN znB^`nhh>U0OzTBr0o;Y7t55pM^1~-jt@}|J$JWE3mnM{b<8kQgWPqE>`vE3APLqNSkMbht*7N3P$tt1raX?sRW*){)hkB3o zgQf@r98lXsxlkZZspsRFJKZI$c8~cJxk(xY1tmND%_Ha=QoniHqm{V>I5pr~{R%OT z!V3yt`%_Sg;Qi}IE05}N(ylkJH`KTGs1_g&3q#KF`&#Rm6slmsqT)1M=TQbAkbahQ z;ChPIDCZj}^$rnls*f3!w2I`9L5ZQpIN|krj_#axfb?tH2;uHBT7_uKj5bQNXN)#R zwC9XAPBfqF)bh};lW@Pl{5(l9(CgEMIGm?7+I$S8R3v^>+Jf_wFvFtIgzFUG5jR0R z6V?aGZlt$pJxMg=8|1&{8x-Rak~c&0#-tr8<}eIOSChYq{usHGRg>5EU^NNv&|D?y1;r9l zQU1f)af}WPjfyqr1&*J#UGuB1o7lbuFKXXgzhh+d*z2~x#E<&(JK$!F^>JW#-59)g zO}VQzAol%AlgFQm2$lh&@ElMb@=jSGGtk=xeuoVzZB|#)7|LTmbb>~0ZEa|Iv%1=& zDS}GUyY~0~z{D@)!U> zH3U+5t^X`&iFhrVuXmJLAu9&Fpitt3rK+NM&WhCz6%nDT9q{OlOU)wRU&A%>^Z%m1 z&N$_!;9q{!cV8rn!JT>`J0EeU{-I=t_xxBJ{ITEj@0p(eJ@@t>dh5QIdhrjf$;L}<^&?EQxN{Wa8kz2SXJ1BykG_YpRrK-$~25bt3j36Yu#;un6$^G1GY J|3AYhu2G@K4xRu2 diff --git a/src/nodes/shaders/vulkan2qsb.sh b/src/nodes/shaders/vulkan2qsb.sh index 765f51272..27639dd4b 100755 --- a/src/nodes/shaders/vulkan2qsb.sh +++ b/src/nodes/shaders/vulkan2qsb.sh @@ -6,6 +6,9 @@ function qsbcompile { # qsb --qt6 -b -o ${qsbfile}.qsb $1 } +qsbcompile arcshadow-vulkan.vert +qsbcompile arcshadow-vulkan.frag + qsbcompile boxshadow-vulkan.vert qsbcompile boxshadow-vulkan.frag