QskBasicLinesNode ( crisplines shaders ) introduced

This commit is contained in:
Uwe Rathmann 2023-11-23 15:38:25 +01:00
parent 16754b4f9d
commit dc64f21901
9 changed files with 296 additions and 0 deletions

View File

@ -97,6 +97,7 @@ list(APPEND SOURCES
list(APPEND HEADERS list(APPEND HEADERS
nodes/QskArcNode.h nodes/QskArcNode.h
nodes/QskBasicLinesNode.h
nodes/QskBoxNode.h nodes/QskBoxNode.h
nodes/QskBoxClipNode.h nodes/QskBoxClipNode.h
nodes/QskBoxFillNode.h nodes/QskBoxFillNode.h
@ -133,6 +134,7 @@ list(APPEND PRIVATE_HEADERS
list(APPEND SOURCES list(APPEND SOURCES
nodes/QskArcNode.cpp nodes/QskArcNode.cpp
nodes/QskBasicLinesNode.cpp
nodes/QskBoxNode.cpp nodes/QskBoxNode.cpp
nodes/QskBoxClipNode.cpp nodes/QskBoxClipNode.cpp
nodes/QskBoxFillNode.cpp nodes/QskBoxFillNode.cpp

View File

@ -0,0 +1,190 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskBasicLinesNode.h"
#include <qsgmaterial.h>
#include <qsggeometry.h>
#include <QTransform>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
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();
}

View File

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

View File

@ -22,5 +22,8 @@
<file>shaders/gradientlinear.vert</file> <file>shaders/gradientlinear.vert</file>
<file>shaders/gradientlinear.frag</file> <file>shaders/gradientlinear.frag</file>
<file>shaders/crisplines.vert.qsb</file>
<file>shaders/crisplines.frag.qsb</file>
</qresource> </qresource>
</RCC> </RCC>

View File

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

View File

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

Binary file not shown.

Binary file not shown.

View File

@ -16,3 +16,6 @@ qsbcompile gradientradial-vulkan.frag
qsbcompile gradientlinear-vulkan.vert qsbcompile gradientlinear-vulkan.vert
qsbcompile gradientlinear-vulkan.frag qsbcompile gradientlinear-vulkan.frag
qsbcompile crisplines-vulkan.vert
qsbcompile crisplines-vulkan.frag