diff --git a/playground/charts/ChartView.cpp b/playground/charts/ChartView.cpp index 6e581d15..c74d5430 100644 --- a/playground/charts/ChartView.cpp +++ b/playground/charts/ChartView.cpp @@ -287,7 +287,8 @@ namespace auto sliderStart = new SliderBox( "Angle", 0.0, 360.0, metrics.startAngle() ); auto sliderSpan = new SliderBox( "Span", -360.0, 360.0, metrics.spanAngle() ); auto sliderExtent = new SliderBox( "Extent", 10.0, 100.0, metrics.thickness() ); - auto shadowExtent = new SliderBox( "Shadow Extent", 0.0, 1.0, 0.5 ); + auto spreadRadius = new SliderBox( "Spread Radius", 0.0, 1.0, 0.01 ); + auto blurRadius = new SliderBox( "Blur Radius", 0.0, 1.0, 0.01 ); auto sliderOffsetX = new SliderBox( "Offset X", -1.0, +1.0, 0 ); auto sliderOffsetY = new SliderBox( "Offset Y", -1.0, +1.0, 0 ); auto sliderStrokeWidth = new SliderBox( "Stroke Width", 0, 10, 1 ); @@ -313,8 +314,11 @@ namespace connect( sliderOffsetY, &SliderBox::valueChanged, this, &ControlPanel::offsetYChanged ); - connect( shadowExtent, &SliderBox::valueChanged, - this, &ControlPanel::shadowExtendChanged ); + connect( spreadRadius, &SliderBox::valueChanged, + this, &ControlPanel::spreadRadiusChanged ); + + connect( blurRadius, &SliderBox::valueChanged, + this, &ControlPanel::blurRadiusChanged ); connect( sliderStrokeWidth, &SliderBox::valueChanged, this, &ControlPanel::strokeWidthChanged ); @@ -336,7 +340,8 @@ namespace addItem( sliderStart, 0, 0 ); addItem( sliderExtent, 0, 1 ); - addItem( shadowExtent, 0, 2 ); + addItem( spreadRadius, 0, 2 ); + addItem( blurRadius, 0, 3 ); addItem( sliderSpan, 1, 0, 1, 1 ); addItem( sliderStrokeWidth, 1, 1, 1, 1 ); addItem( sliderOffsetX, 2, 0, 1, 1 ); @@ -355,7 +360,8 @@ namespace void fillColorChanged( QColor ); void strokeColorChanged( QColor ); void shadowColorChanged( QColor ); - void shadowExtendChanged( qreal ); + void spreadRadiusChanged( qreal ); + void blurRadiusChanged( qreal ); void strokeWidthChanged( qreal ); }; @@ -461,12 +467,18 @@ ChartView::ChartView( ArcControl* chart, QQuickItem* parent ) chart->setShadowMetricsHint( subcontrol, h ); } ); - connect( controlPanel, &ControlPanel::shadowExtendChanged, chart, [ = ]( qreal v ) { + connect( controlPanel, &ControlPanel::spreadRadiusChanged, chart, [ = ]( qreal v ) { auto h = chart->shadowMetricsHint( subcontrol ); h.setSpreadRadius( v ); chart->setShadowMetricsHint( subcontrol, h ); } ); + connect( controlPanel, &ControlPanel::blurRadiusChanged, chart, [ = ]( qreal v ) { + auto h = chart->shadowMetricsHint( subcontrol ); + h.setBlurRadius( v ); + chart->setShadowMetricsHint( subcontrol, h ); + } ); + connect( controlPanel, &ControlPanel::fillColorChanged, chart, [ = ]( QColor c ) { chart->setColor( subcontrol, c ); } ); diff --git a/playground/charts/main.cpp b/playground/charts/main.cpp index 5b5397c0..2010fda4 100644 --- a/playground/charts/main.cpp +++ b/playground/charts/main.cpp @@ -129,7 +129,8 @@ int main( int argc, char* argv[] ) metrics.setThickness(10); QskShadowMetrics shadowMetrics; - shadowMetrics.setSpreadRadius(0.1); + shadowMetrics.setSpreadRadius(0.01); + shadowMetrics.setBlurRadius(0.01); shadowMetrics.setSizeMode(Qt::SizeMode::RelativeSize); control->setGradientHint(Q::Arc, {Qt::red}); diff --git a/src/nodes/QskArcShadowNode.cpp b/src/nodes/QskArcShadowNode.cpp index 3a4c0c16..b683f1da 100644 --- a/src/nodes/QskArcShadowNode.cpp +++ b/src/nodes/QskArcShadowNode.cpp @@ -37,14 +37,15 @@ namespace float thickness = 0.0f; float startAngle = 0.0f; float spanAngle = M_PI; - float extend = 0.0f; + float spreadRadius = 0.0f; + float blurRadius = 0.0f; Q_REQUIRED_RESULT inline bool operator==(const MaterialProperties& rhs) const noexcept { return color == rhs.color && offset == rhs.offset && radius == rhs.radius && thickness == rhs.thickness && startAngle == rhs.startAngle && spanAngle == rhs.spanAngle && - extend == rhs.extend; + spreadRadius == rhs.spreadRadius && blurRadius == rhs.blurRadius; } Q_REQUIRED_RESULT inline bool operator!=(const MaterialProperties& rhs) const noexcept @@ -81,7 +82,7 @@ namespace MaterialProperties properties; float opacity = 1.0f; - static_assert(sizeof(properties) == sizeof(float) * 11, "Layout mustn't have trailing paddings"); + static_assert(sizeof(properties) == sizeof(float) * 12, "Assuming packed layout!"); }; public: @@ -138,7 +139,8 @@ namespace int thickness = -1; int startAngle = -1; int spanAngle = -1; - int extend = -1; + int spreadRadius = -1; + int blurRadius = -1; }; public: @@ -168,7 +170,8 @@ namespace id.thickness = p->uniformLocation( "thickness" ); id.startAngle = p->uniformLocation( "startAngle" ); id.spanAngle = p->uniformLocation( "spanAngle" ); - id.extend = p->uniformLocation( "extend" ); + id.spreadRadius = p->uniformLocation( "spreadRadius" ); + id.blurRadius = p->uniformLocation( "blurRadius" ); } void updateState( const QSGMaterialShader::RenderState& state, @@ -201,7 +204,8 @@ namespace p->setUniformValue( id.thickness, properties.thickness); p->setUniformValue( id.startAngle, properties.startAngle); p->setUniformValue( id.spanAngle, properties.spanAngle); - p->setUniformValue( id.extend, properties.extend); + p->setUniformValue( id.spreadRadius, properties.spreadRadius); + p->setUniformValue( id.blurRadius, properties.blurRadius); } } @@ -370,6 +374,17 @@ void QskArcShadowNode::update( const QRectF& rect, const QskArcMetrics& arcMetri } (shadowMetrics, shadowRect); + const auto blurRadius = [](const QskShadowMetrics& metrics, const QRectF& rect){ + auto blurRadius = metrics.blurRadius(); + const auto size = qMin( rect.width(), rect.height() ); + if ( metrics.sizeMode() == Qt::AbsoluteSize ) + { + blurRadius = blurRadius / size; + } + blurRadius = qBound( 0.0, blurRadius, 1.0 ); + return (float) blurRadius; + }(shadowMetrics, shadowRect); + const auto startAngle = (float) qDegreesToRadians(arcMetrics.startAngle() + 90.0); // why +90 ? const auto spanAngle = (float) qDegreesToRadians(arcMetrics.spanAngle()); const auto radius = ( float ) ( 1.0 - thickness - 2 * w / size ); @@ -381,7 +396,8 @@ void QskArcShadowNode::update( const QRectF& rect, const QskArcMetrics& arcMetri thickness, startAngle, spanAngle, - spreadRadius + spreadRadius, + blurRadius }; const auto dirtyGeometry = ( d->rect != shadowRect ); diff --git a/src/nodes/shaders/arcshadow-vulkan.frag b/src/nodes/shaders/arcshadow-vulkan.frag index 21f01210..de730320 100644 --- a/src/nodes/shaders/arcshadow-vulkan.frag +++ b/src/nodes/shaders/arcshadow-vulkan.frag @@ -6,14 +6,15 @@ layout( location = 0 ) out vec4 fragColor; layout( std140, binding = 0 ) uniform buf { mat4 matrix; - vec4 color; // shadow's color - vec2 offset; // shadow's offset (x,y) : [-1.0, +1.0]x[-1.0,+1.0] - float radius; // arc's radius [0.0, 1.0] - float thickness; // arc's thickness [0.0, 1.0] - float startAngle; // arc's start angle [rad] - float spanAngle; // arc's span angle [rad] - float extend; // shadow length [0.0, 1.0] - float opacity; // overall opacity [0.0, 1.0] + vec4 color; // shadow's color + vec2 offset; // shadow's offset (x,y) : [-1.0, +1.0]x[-1.0,+1.0] + float radius; // arc's radius [0.0, 1.0] + float thickness; // arc's thickness [0.0, 1.0] + float startAngle; // arc's start angle [rad] + float spanAngle; // arc's span angle [rad] + float spreadRadius; // extended shadow length [0.0, 1.0] + float blurRadius; // extended shadow blurring length [0.0, 1.0] + float opacity; // overall opacity [0.0, 1.0] } ubuf; float sdRing( in vec2 p, in vec2 n, in float r, in float th ) @@ -45,8 +46,8 @@ void main() float t = abs(ubuf.spanAngle) / 2.0; // half span angle vec2 cs = vec2(cos(t),sin(t)); - float d = sdRing(p, cs, ubuf.radius / 2.0, ubuf.thickness); + float d = sdRing(p, cs, ubuf.radius / 2.0, ubuf.thickness + spreadRadius); - float a = 1.0 - smoothstep(0.0, ubuf.extend, d); + float a = 1.0 - smoothstep(0.0, ubuf.blurRadius, d); fragColor = ubuf.color * a * ubuf.opacity; } \ No newline at end of file diff --git a/src/nodes/shaders/arcshadow.frag b/src/nodes/shaders/arcshadow.frag index 5ad0e2a7..e17f29b5 100644 --- a/src/nodes/shaders/arcshadow.frag +++ b/src/nodes/shaders/arcshadow.frag @@ -1,15 +1,15 @@ -uniform lowp mat4 matrix; -uniform lowp float radius; // arc's radius [0.0, 1.0] -uniform lowp float thickness; // arc's thickness [0.0, 1.0] -uniform lowp float startAngle; // arc's start angle [rad] -uniform lowp float spanAngle; // arc's span angle [rad] -uniform lowp vec4 color; // shadow's color -uniform lowp vec2 offset; // shadow's offset (x,y) : [-1.0, +1.0]x[-1.0,+1.0] -uniform lowp float extend; // shadow length [0.0, 1.0] -uniform lowp float opacity; // overall opacity [0.0, 1.0] +varying lowp vec2 coord; // [-1.0,+1.0]x[-1.0,+1.0] -// position -varying lowp vec2 coord; // [-1.0,+1.0]x[-1.0,+1.0] +uniform lowp mat4 matrix; +uniform lowp vec4 color; // shadow's color +uniform lowp vec2 offset; // shadow's offset (x,y) : [-1.0, +1.0]x[-1.0,+1.0] +uniform lowp float radius; // arc's radius [0.0, 1.0] +uniform lowp float thickness; // arc's thickness [0.0, 1.0] +uniform lowp float startAngle; // arc's start angle [rad] +uniform lowp float spanAngle; // arc's span angle [rad] +uniform lowp float spreadRadius; // extended shadow length [0.0, 1.0] +uniform lowp float blurRadius; // extended shadow blurring length [0.0, 1.0] +uniform lowp float opacity; // overall opacity [0.0, 1.0] float sdRing( in vec2 p, in vec2 n, in float r, in float th ) { @@ -40,8 +40,8 @@ void main() float t = abs(spanAngle) / 2.0; // half span angle vec2 cs = vec2(cos(t),sin(t)); - float d = sdRing(p, cs, radius / 2.0, thickness); + float d = sdRing(p, cs, radius / 2.0, thickness + spreadRadius); - float a = 1.0 - smoothstep(0.0, extend, d); + float a = 1.0 - smoothstep(0.0, blurRadius, d); gl_FragColor = color * a * opacity; } \ No newline at end of file