diff --git a/src/nodes/QskArcNode.cpp b/src/nodes/QskArcNode.cpp index 7f1eea7a..d4e5ef0c 100644 --- a/src/nodes/QskArcNode.cpp +++ b/src/nodes/QskArcNode.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include #include diff --git a/src/nodes/QskArcShadowNode.cpp b/src/nodes/QskArcShadowNode.cpp index 05a237d7..bbd07bf9 100644 --- a/src/nodes/QskArcShadowNode.cpp +++ b/src/nodes/QskArcShadowNode.cpp @@ -73,17 +73,44 @@ namespace { class ShaderRhi final : public RhiShader { + struct UniformBuffer + { + float matrix[4][4]; + MaterialProperties properties; + float opacity = 1.0f; + + static_assert(sizeof(properties) == sizeof(float) * 11, "Layout mustn't have trailing paddings"); + }; + public: ShaderRhi() { - // TODO + const QString root( ":/qskinny/shaders/" ); + setShaderFileName( VertexStage, root + "arcshadow.vert.qsb" ); + setShaderFileName( FragmentStage, root + "arcshadow.frag.qsb" ); } bool updateUniformData( RenderState& state, - QSGMaterial* newMaterial, QSGMaterial* oldMaterial ) override + QSGMaterial* const newMaterial, QSGMaterial* const oldMaterial ) override { - // TODO - return false; + const auto matOld = static_cast< Material* >( oldMaterial ); + const auto matNew = static_cast< Material* >( newMaterial ); + + const bool dirty = matOld == nullptr || state.isOpacityDirty() || state.isMatrixDirty() || + matOld->compare( matNew ) != 0; + + UniformBuffer buffer; + + const auto dstBufferSize = state.uniformData()->size(); + const auto srcBufferSize = sizeof(buffer); + Q_ASSERT( dstBufferSize >= srcBufferSize ); + + auto* data = state.uniformData()->data(); + std::memcpy(buffer.matrix, state.combinedMatrix().constData(), sizeof(buffer.matrix)); + buffer.properties = matNew->properties; + std::memcpy(data, &buffer, sizeof(buffer)); + + return dirty; } }; } @@ -215,7 +242,7 @@ namespace return &staticType; } - int Material::compare( const QSGMaterial* other ) const + int Material::compare( const QSGMaterial* const other ) const { const auto& lhs = *static_cast< const Material* >( this ); const auto& rhs = *static_cast< const Material* >( other ); @@ -275,7 +302,7 @@ void QskArcShadowNode::update( const QRectF& rect, const QskArcMetrics& arcMetri const QColor& shadowColor, const QskShadowMetrics& shadowMetrics, const qreal borderWidth ) { Q_D( QskArcShadowNode ); - + const auto w = qMax(0.0, borderWidth); const auto shadowRect = rect.adjusted(-w, -w, +w, +w); const auto size = qMin( shadowRect.width(), shadowRect.height() ); diff --git a/src/nodes/QskArcShadowNode.h b/src/nodes/QskArcShadowNode.h index 7747a7e5..c69e3e9d 100644 --- a/src/nodes/QskArcShadowNode.h +++ b/src/nodes/QskArcShadowNode.h @@ -20,8 +20,8 @@ class QskArcShadowNode : public QSGGeometryNode QskArcShadowNode(); ~QskArcShadowNode() override; - void update( const QRectF& rect, const QskArcMetrics& metrics, const QColor& color, - const QskShadowMetrics& shadowMetrics, qreal borderWidth = 0.0 ); + void update( const QRectF& rect, const QskArcMetrics& arcMetrics, const QColor& shadowColor, + const QskShadowMetrics& shadowMetrics, qreal borderWidth ); private: Q_DECLARE_PRIVATE( QskArcShadowNode ) diff --git a/src/nodes/shaders.qrc b/src/nodes/shaders.qrc index 7f74a1ac..7d2d15a4 100644 --- a/src/nodes/shaders.qrc +++ b/src/nodes/shaders.qrc @@ -4,6 +4,8 @@ shaders/arcshadow.frag shaders/arcshadow.vert + shaders/arcshadow.frag.qsb + shaders/arcshadow.vert.qsb shaders/boxshadow.vert.qsb shaders/boxshadow.frag.qsb diff --git a/src/nodes/shaders/arcshadow-vulkan.frag b/src/nodes/shaders/arcshadow-vulkan.frag new file mode 100644 index 00000000..69a6929e --- /dev/null +++ b/src/nodes/shaders/arcshadow-vulkan.frag @@ -0,0 +1,52 @@ +#version 440 + +layout( location = 0 ) in vec2 coord; // [-1.0,+1.0]x[-1.0,+1.0] +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] +} ubuf; + +float sdRing( in vec2 p, in vec2 n, in float r, in float th ) +{ + p.x = abs(p.x); + + p = mat2(n.x,n.y,-n.y,n.x)*p; + + return max( abs(length(p)-r)-th*0.5, + length(vec2(p.x,max(0.0,abs(r-p.y)-th*0.5)))*sign(p.x) ); +} + +void main() +{ + // rotation + vec2 p = coord + ubuf.offset; + float ra = -ubuf.startAngle - ubuf.spanAngle / 2.0; + { + float sin_ra = sin(ra); + float cos_ra = cos(ra); + mat2 transform = mat2 + ( + cos_ra, -sin_ra, + sin_ra, cos_ra + ); + + p = transform * p; + } + + 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 a = 1.0 - smoothstep(0.0, ubuf.extend, d); + fragColor = vec4(ubuf.color.rgb, 1.0) * a * ubuf.opacity; +} \ No newline at end of file diff --git a/src/nodes/shaders/arcshadow-vulkan.vert b/src/nodes/shaders/arcshadow-vulkan.vert new file mode 100644 index 00000000..177e20d0 --- /dev/null +++ b/src/nodes/shaders/arcshadow-vulkan.vert @@ -0,0 +1,16 @@ +#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; +} 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 index 7e2bef1c..2d44a320 100644 --- a/src/nodes/shaders/arcshadow.frag +++ b/src/nodes/shaders/arcshadow.frag @@ -1,13 +1,13 @@ -uniform lowp float opacity; -// arc +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] -// shadow 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] + // position varying lowp vec2 coord; // [-1.0,+1.0]x[-1.0,+1.0] diff --git a/src/nodes/shaders/arcshadow.frag.qsb b/src/nodes/shaders/arcshadow.frag.qsb new file mode 100644 index 00000000..435e2fe9 Binary files /dev/null and b/src/nodes/shaders/arcshadow.frag.qsb differ diff --git a/src/nodes/shaders/arcshadow.vert.qsb b/src/nodes/shaders/arcshadow.vert.qsb new file mode 100644 index 00000000..a3f754ce Binary files /dev/null and b/src/nodes/shaders/arcshadow.vert.qsb differ diff --git a/src/nodes/shaders/vulkan2qsb.sh b/src/nodes/shaders/vulkan2qsb.sh index 22e28e10..0ace7a2d 100755 --- a/src/nodes/shaders/vulkan2qsb.sh +++ b/src/nodes/shaders/vulkan2qsb.sh @@ -5,6 +5,9 @@ function qsbcompile { qsb --glsl 100es,120,150 --hlsl 50 --msl 12 -b -o ${qsbfile}.qsb $1 } +qsbcompile arcshadow-vulkan.vert +qsbcompile arcshadow-vulkan.frag + qsbcompile boxshadow-vulkan.vert qsbcompile boxshadow-vulkan.frag