From dc64f219016caff1f3b69ce60937873b8be8c829 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 23 Nov 2023 15:38:25 +0100 Subject: [PATCH] QskBasicLinesNode ( crisplines shaders ) introduced --- src/CMakeLists.txt | 2 + src/nodes/QskBasicLinesNode.cpp | 190 +++++++++++++++++++++++ src/nodes/QskBasicLinesNode.h | 42 +++++ src/nodes/shaders.qrc | 3 + src/nodes/shaders/crisplines-vulkan.frag | 15 ++ src/nodes/shaders/crisplines-vulkan.vert | 41 +++++ src/nodes/shaders/crisplines.frag.qsb | Bin 0 -> 870 bytes src/nodes/shaders/crisplines.vert.qsb | Bin 0 -> 2512 bytes src/nodes/shaders/vulkan2qsb.sh | 3 + 9 files changed, 296 insertions(+) create mode 100644 src/nodes/QskBasicLinesNode.cpp create mode 100644 src/nodes/QskBasicLinesNode.h create mode 100644 src/nodes/shaders/crisplines-vulkan.frag create mode 100644 src/nodes/shaders/crisplines-vulkan.vert create mode 100644 src/nodes/shaders/crisplines.frag.qsb create mode 100644 src/nodes/shaders/crisplines.vert.qsb diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b626e406..a6ff444a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -97,6 +97,7 @@ list(APPEND SOURCES list(APPEND HEADERS nodes/QskArcNode.h + nodes/QskBasicLinesNode.h nodes/QskBoxNode.h nodes/QskBoxClipNode.h nodes/QskBoxFillNode.h @@ -133,6 +134,7 @@ list(APPEND PRIVATE_HEADERS list(APPEND SOURCES nodes/QskArcNode.cpp + nodes/QskBasicLinesNode.cpp nodes/QskBoxNode.cpp nodes/QskBoxClipNode.cpp nodes/QskBoxFillNode.cpp diff --git a/src/nodes/QskBasicLinesNode.cpp b/src/nodes/QskBasicLinesNode.cpp new file mode 100644 index 00000000..a4e41df0 --- /dev/null +++ b/src/nodes/QskBasicLinesNode.cpp @@ -0,0 +1,190 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskBasicLinesNode.h" + +#include +#include +#include + +QSK_QT_PRIVATE_BEGIN +#include +QSK_QT_PRIVATE_END + +namespace +{ + class Material final : public QSGMaterial + { + public: + Material(); + + QSGMaterialShader* createShader( QSGRendererInterface::RenderMode ) const override; + + QSGMaterialType* type() const override; + + int compare( const QSGMaterial* other ) const override; + + QVector4D m_color = QVector4D{ 0, 0, 0, 1 }; + Qt::Orientations m_pixelAlignment; + }; + + class ShaderRhi final : public QSGMaterialShader + { + public: + + ShaderRhi() + { + const QString root( ":/qskinny/shaders/" ); + + setShaderFileName( VertexStage, root + "crisplines.vert.qsb" ); + setShaderFileName( FragmentStage, root + "crisplines.frag.qsb" ); + } + + bool updateUniformData( RenderState& state, + QSGMaterial* newMaterial, QSGMaterial* oldMaterial ) override + { + auto matOld = static_cast< Material* >( oldMaterial ); + auto matNew = static_cast< Material* >( newMaterial ); + + Q_ASSERT( state.uniformData()->size() >= 88 ); + + auto data = state.uniformData()->data(); + bool changed = false; + + const auto matrix = state.combinedMatrix(); + + if ( state.isMatrixDirty() ) + { + 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 ( state.isMatrixDirty() || ( matOld == nullptr ) + || ( matNew->m_pixelAlignment != matOld->m_pixelAlignment ) ) + { + /* + We do not need to upload the size as it is available + from the matrix. But the shader needs to know wether to + round or not TODO ... + */ + QVector2D size; + + if ( matNew->m_pixelAlignment & Qt::Horizontal ) + size.setX( 2.0 / matrix( 0, 0 ) ); + + if ( matNew->m_pixelAlignment & Qt::Vertical ) + size.setY( -2.0 / matrix( 1, 1 ) ); + + memcpy( data + 80, &size, 8 ); + changed = true; + } + + return changed; + } + }; +} + +Material::Material() +{ +} + +QSGMaterialShader* Material::createShader( QSGRendererInterface::RenderMode ) const +{ + return new ShaderRhi(); +} + +QSGMaterialType* Material::type() const +{ + static QSGMaterialType staticType; + return &staticType; +} + +int Material::compare( const QSGMaterial* other ) const +{ + auto material = static_cast< const Material* >( other ); + + if ( material->m_color == m_color ) + return 0; + + return QSGMaterial::compare( other ); +} + +class QskBasicLinesNodePrivate final : public QSGGeometryNodePrivate +{ + public: + QskBasicLinesNodePrivate() + : geometry( QSGGeometry::defaultAttributes_Point2D(), 0 ) + { + geometry.setDrawingMode( QSGGeometry::DrawLines ); + } + + QSGGeometry geometry; + Material material; +}; + +QskBasicLinesNode::QskBasicLinesNode() + : QSGGeometryNode( *new QskBasicLinesNodePrivate ) +{ + Q_D( QskBasicLinesNode ); + + setGeometry( &d->geometry ); + setMaterial( &d->material ); +} + +QskBasicLinesNode::~QskBasicLinesNode() +{ +} + +void QskBasicLinesNode::setPixelAlignment( Qt::Orientations orientations ) +{ + Q_D( QskBasicLinesNode ); + + if ( orientations != d->material.m_pixelAlignment ) + { + d->material.m_pixelAlignment = orientations; + markDirty( QSGNode::DirtyMaterial ); + } +} + +Qt::Orientations QskBasicLinesNode::pixelAlignment() const +{ + return d_func()->material.m_pixelAlignment; +} + +void QskBasicLinesNode::setColor( const QColor& color ) +{ + Q_D( QskBasicLinesNode ); + + const auto a = color.alphaF(); + + const QVector4D c( color.redF() * a, color.greenF() * a, color.blueF() * a, a ); + + if ( c != d->material.m_color ) + { + d->material.m_color = c; + markDirty( QSGNode::DirtyMaterial ); + } +} + +void QskBasicLinesNode::setLineWidth( float lineWidth ) +{ + Q_D( QskBasicLinesNode ); + + lineWidth = std::max( lineWidth, 0.0f ); + if( lineWidth != d->geometry.lineWidth() ) + d->geometry.setLineWidth( lineWidth ); +} + +float QskBasicLinesNode::lineWidth() const +{ + return d_func()->geometry.lineWidth(); +} + diff --git a/src/nodes/QskBasicLinesNode.h b/src/nodes/QskBasicLinesNode.h new file mode 100644 index 00000000..607c9cc5 --- /dev/null +++ b/src/nodes/QskBasicLinesNode.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_BASIC_LINES_NODE_H +#define QSK_BASIC_LINES_NODE_H + +#include "QskGlobal.h" + +#include +#include + +class QColor; + +class QskBasicLinesNodePrivate; + +/* + A node for stippled or solid lines. + For the moment limited to horizontal/vertical lines: TODO + */ +class QSK_EXPORT QskBasicLinesNode : public QSGGeometryNode +{ + using Inherited = QSGGeometryNode; + + public: + QskBasicLinesNode(); + ~QskBasicLinesNode() override; + + void setPixelAlignment( Qt::Orientations ); + Qt::Orientations pixelAlignment() const; + + void setColor( const QColor& ); + + void setLineWidth( float ); + float lineWidth() const; + + private: + Q_DECLARE_PRIVATE( QskBasicLinesNode ) +}; + +#endif diff --git a/src/nodes/shaders.qrc b/src/nodes/shaders.qrc index 0301b991..d87dec16 100644 --- a/src/nodes/shaders.qrc +++ b/src/nodes/shaders.qrc @@ -22,5 +22,8 @@ shaders/gradientlinear.vert shaders/gradientlinear.frag + shaders/crisplines.vert.qsb + shaders/crisplines.frag.qsb + diff --git a/src/nodes/shaders/crisplines-vulkan.frag b/src/nodes/shaders/crisplines-vulkan.frag new file mode 100644 index 00000000..a4618fe9 --- /dev/null +++ b/src/nodes/shaders/crisplines-vulkan.frag @@ -0,0 +1,15 @@ +#version 440 + +layout( location = 0 ) out vec4 fragColor; + +layout( std140, binding = 0 ) uniform buf +{ + mat4 matrix; + vec4 color; + vec2 size; +} ubuf; + +void main() +{ + fragColor = ubuf.color; +} diff --git a/src/nodes/shaders/crisplines-vulkan.vert b/src/nodes/shaders/crisplines-vulkan.vert new file mode 100644 index 00000000..e572cda7 --- /dev/null +++ b/src/nodes/shaders/crisplines-vulkan.vert @@ -0,0 +1,41 @@ +#version 440 + +layout( location = 0 ) in vec4 vertexCoord; + +layout( std140, binding = 0 ) uniform buf +{ + mat4 matrix; + vec4 color; + vec2 size; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +float normalized( in float pos, in float scale, in float size ) +{ + return ( ( pos / size - 0.5 ) / 0.5 ) * scale; +} + +float denormalized( in float pos, in float scale, in float size ) +{ + return ( ( pos / scale ) * 0.5 + 0.5 ) * size; +} + +void main() +{ + gl_Position = ubuf.matrix * vertexCoord; + + if ( ubuf.size.x > 0.0 ) + { + gl_Position.x = denormalized( gl_Position.x, gl_Position.w, ubuf.size.x ); + gl_Position.x = round( gl_Position.x ) + 0.5; + gl_Position.x = normalized( gl_Position.x, gl_Position.w, ubuf.size.x ); + } + + if ( ubuf.size.y > 0.0 ) + { + gl_Position.y = denormalized( gl_Position.y, gl_Position.w, ubuf.size.y ); + gl_Position.y = round( gl_Position.y ) + 0.5; + gl_Position.y = normalized( gl_Position.y, gl_Position.w, ubuf.size.y ); + } +} diff --git a/src/nodes/shaders/crisplines.frag.qsb b/src/nodes/shaders/crisplines.frag.qsb new file mode 100644 index 0000000000000000000000000000000000000000..7d310ef430750d50e7f8934192945920beae2f07 GIT binary patch literal 870 zcmV-s1DX5)0113}oXu8kYZE~b-X>|&Uix0&KFMi75`=h$RK(a)srUi~i1pmR+)E8D`4{3Z@Q3)>U*s3jncca&LWGRBq|V-+UH9L!DT zu#j17!1h_dhA_hv@rwqVF)(z2^;iPoj4i@DUB6dQWthv%1NsLi@|axgvCyzUyGGQ9fAveX`fd#`q1wBIhGG zqr~!01M~U;9@P37JQ2G|{K&CGHExlA7b2F({s|{M7N@WZ^%spky>Wc2pYt$s17Ck= z7}_Z0wkxbNcW^e+onc_b-6^;0gHwy*FtKC3mpIy`ro-^8xPy<-9e0J}oZB7U4u(OP z*=;>?FL+m*072rrP7r#?peOJE*LmRfbxgIZ;7^nJfj0aKK|jvI{K{ zU|uPxnF~67+H^07Ox8Ig07@EgGZ2OZsh*a4x>B#`2#=G{FAz-BE?4M>E$#AA-SzEZ z(&ze9kH^-~gg-7rx3{b1{>b(E5Ae}C+l6Zwx&A=+Essag53Y--S-&6Iolx&MX|CLI z>T`b2i3syGu!cW%>*PeRG>qoysf@%ukNZljTs7>#2T6R9-96DUh?ciogg3KKGL6Hz wqhC&BjzK|n^&?Vb52V^C_q?E@ud486Wxv*p{tGJfWNJV46>(zx2Ir*U1E+AeoB#j- literal 0 HcmV?d00001 diff --git a/src/nodes/shaders/crisplines.vert.qsb b/src/nodes/shaders/crisplines.vert.qsb new file mode 100644 index 0000000000000000000000000000000000000000..bff4576922ce44691ed1c04677ca296d67de2491 GIT binary patch literal 2512 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 a!z