QskArcShadowNode introduced ( kudos to Rick )

This commit is contained in:
Uwe Rathmann 2024-01-06 15:05:30 +01:00
parent a420407a56
commit e63b064f5a
32 changed files with 1309 additions and 193 deletions

View File

@ -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 <QskGridBox.h>
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"

View File

@ -0,0 +1,14 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskLinearBox.h>
class ArcPage : public QskLinearBox
{
public:
ArcPage( QQuickItem* parent = nullptr );
};

View File

@ -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 <QskRgbValue.h>
#include <QFontMetrics>
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 );
}

View File

@ -0,0 +1,19 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskLinearBox.h>
class QskSlider;
class BoxPage : public QskLinearBox
{
public:
BoxPage( QQuickItem* parent = nullptr );
private:
void addSlider( int row, const QString&, QskSlider* );
};

View File

@ -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)

View File

@ -0,0 +1,269 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "ShadowedArc.h"
#include <QskSkinlet.h>
#include <QskArcNode.h>
#include <QskArcMetrics.h>
#include <QskShadowMetrics.h>
#include <QskArcNode.h>
#include <QskSGNode.h>
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"

View File

@ -0,0 +1,64 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskControl.h>
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& );
};

View File

@ -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 );
}

View File

@ -0,0 +1,47 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "Slider.h"
#include <QskSlider.h>
#include <QskTextLabel.h>
#include <qfontmetrics.h>
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"

View File

@ -0,0 +1,37 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskLinearBox.h>
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;
};

View File

@ -3,129 +3,31 @@
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "ShadowedBox.h"
#include "BoxPage.h"
#include "ArcPage.h"
#include <QskObjectCounter.h>
#include <QskWindow.h>
#include <QskGridBox.h>
#include <QskSlider.h>
#include <QskTextLabel.h>
#include <QskRgbValue.h>
#include <QskTabView.h>
#include <QskTabBar.h>
#include <SkinnyShortcut.h>
#include <QGuiApplication>
#include <QFontMetrics>
class BoxPanel : public QskBox
namespace
{
public:
BoxPanel( QQuickItem* parent = nullptr )
: QskBox( parent )
class TabView : public QskTabView
{
setAutoLayoutChildren( true );
setPadding( 60 );
public:
TabView()
{
//setTabBarEdge( Qt::LeftEdge );
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 ) ); } );
}
};
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();

View File

@ -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

View File

@ -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() )

View File

@ -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 <qpen.h>
#include <qpainterpath.h>
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, {}, {} );
}
const auto metrics = qskEffectiveMetrics( arcMetrics, rect );
const auto gradient = qskEffectiveGradient( fillGradient, metrics );
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 );
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);
}

View File

@ -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

View File

@ -0,0 +1,368 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskArcShadowNode.h"
#include <qcolor.h>
#include <qsgmaterial.h>
#include <qsgmaterialshader.h>
#include <qmath.h>
#include <cstring>
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;
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 );
}

View File

@ -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 <qsgnode.h>
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

View File

@ -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 );
}
}

View File

@ -2,6 +2,11 @@
<RCC version="1.0">
<qresource prefix="/qskinny/">
<file>shaders/arcshadow.frag</file>
<file>shaders/arcshadow.vert</file>
<file>shaders/arcshadow.frag.qsb</file>
<file>shaders/arcshadow.vert.qsb</file>
<file>shaders/boxshadow.vert.qsb</file>
<file>shaders/boxshadow.frag.qsb</file>
<file>shaders/boxshadow.vert</file>

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

Binary file not shown.

View File

@ -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;
}

Binary file not shown.

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

Binary file not shown.

Binary file not shown.

View File

@ -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