QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskBasicLinesNode.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskBasicLinesNode.h"
7
8#include <qsgmaterial.h>
9#include <qsggeometry.h>
10#include <QTransform>
11
12QSK_QT_PRIVATE_BEGIN
13#include <private/qsgnode_p.h>
14QSK_QT_PRIVATE_END
15
16static inline QVector4D qskColorVector( const QColor& c, qreal opacity)
17{
18 const auto a = c.alphaF() * opacity;
19 return QVector4D( c.redF() * a, c.greenF() * a, c.blueF() * a, a );
20}
21
22static inline QVector2D qskOrigin(
23 const QRect& rect, Qt::Orientations orientations )
24{
25 return QVector2D(
26 ( orientations & Qt::Horizontal ) ? 0.5 * rect.width() : 0.0,
27 ( orientations & Qt::Vertical ) ? 0.5 * rect.height() : 0.0
28 );
29}
30
31#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
32 #include <QSGMaterialRhiShader>
33 using RhiShader = QSGMaterialRhiShader;
34#else
35 using RhiShader = QSGMaterialShader;
36#endif
37
38namespace
39{
40 class Material final : public QSGMaterial
41 {
42 public:
43 Material();
44
45#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
46 QSGMaterialShader* createShader() const override;
47#else
48 QSGMaterialShader* createShader( QSGRendererInterface::RenderMode ) const override;
49#endif
50
51 QSGMaterialType* type() const override;
52
53 int compare( const QSGMaterial* other ) const override;
54
55 QColor m_color = QColor( 255, 255, 255 );
56 Qt::Orientations m_pixelAlignment;
57 };
58
59 class ShaderRhi final : public RhiShader
60 {
61 public:
62
63 ShaderRhi()
64 {
65 const QString root( ":/qskinny/shaders/" );
66
67 setShaderFileName( VertexStage, root + "crisplines.vert.qsb" );
68 setShaderFileName( FragmentStage, root + "crisplines.frag.qsb" );
69 }
70
71 bool updateUniformData( RenderState& state,
72 QSGMaterial* newMaterial, QSGMaterial* oldMaterial ) override
73 {
74 auto matOld = static_cast< Material* >( oldMaterial );
75 auto matNew = static_cast< Material* >( newMaterial );
76
77 Q_ASSERT( state.uniformData()->size() >= 88 );
78
79 auto data = state.uniformData()->data();
80 bool changed = false;
81
82 const auto matrix = state.combinedMatrix();
83
84 if ( state.isMatrixDirty() )
85 {
86 memcpy( data + 0, matrix.constData(), 64 );
87 changed = true;
88 }
89
90 if ( ( matOld == nullptr ) || ( matNew->m_color != matOld->m_color )
91 || state.isOpacityDirty() )
92 {
93 const auto v4 = qskColorVector( matNew->m_color, state.opacity() );
94 memcpy( data + 64, &v4, 16 );
95 changed = true;
96 }
97
98 if ( state.isMatrixDirty() || ( matOld == nullptr )
99 || ( matNew->m_pixelAlignment != matOld->m_pixelAlignment ) )
100 {
101 /*
102 The shaders work with coordinates in the range[-1,1]. When knowing
103 the device coordinates corresponding to [0.0] we can scale a vertex
104 into device coordinates.
105
106 coordinates <= 0.0 indicate, that no rounding should be done.
107 */
108 const auto origin = qskOrigin(
109 state.viewportRect(), matNew->m_pixelAlignment );
110
111 memcpy( data + 80, &origin, 8 );
112 changed = true;
113 }
114
115 return changed;
116 }
117 };
118}
119
120#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
121
122namespace
123{
124 // the old type of shader - spcific for OpenGL
125
126 class ShaderGL final : public QSGMaterialShader
127 {
128 public:
129 ShaderGL()
130 {
131 const QString root( ":/qskinny/shaders/" );
132
133 setShaderSourceFile( QOpenGLShader::Vertex,
134 ":/qskinny/shaders/crisplines.vert" );
135
136 setShaderSourceFile( QOpenGLShader::Fragment,
137 ":/qt-project.org/scenegraph/shaders/flatcolor.frag" );
138 }
139
140 char const* const* attributeNames() const override
141 {
142 static char const* const names[] = { "in_vertex", nullptr };
143 return names;
144 }
145
146 void initialize() override
147 {
148 QSGMaterialShader::initialize();
149
150 auto p = program();
151
152 m_matrixId = p->uniformLocation( "matrix" );
153 m_colorId = p->uniformLocation( "color" );
154 m_originId = p->uniformLocation( "origin" );
155 }
156
157 void updateState( const QSGMaterialShader::RenderState& state,
158 QSGMaterial* newMaterial, QSGMaterial* oldMaterial) override
159 {
160 auto p = program();
161
162 const auto matrix = state.combinedMatrix();
163
164 if ( state.isMatrixDirty() )
165 p->setUniformValue( m_matrixId, matrix );
166
167 bool updateMaterial = ( oldMaterial == nullptr )
168 || newMaterial->compare( oldMaterial ) != 0;
169
170 updateMaterial |= state.isCachedMaterialDataDirty();
171
172 if ( updateMaterial )
173 {
174 auto material = static_cast< const Material* >( newMaterial );
175
176 p->setUniformValue( m_colorId,
177 qskColorVector( material->m_color, state.opacity() ) );
178
179 const auto origin = qskOrigin(
180 state.viewportRect(), material->m_pixelAlignment );;
181 p->setUniformValue( m_originId, origin );
182 }
183 }
184
185 private:
186 int m_matrixId = -1;
187 int m_colorId = -1;
188 int m_originId = -1;
189 };
190}
191
192#endif
193
194Material::Material()
195{
196#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
197 setFlag( QSGMaterial::SupportsRhiShader, true );
198#endif
199}
200
201#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
202
203QSGMaterialShader* Material::createShader() const
204{
205 if ( !( flags() & QSGMaterial::RhiShaderWanted ) )
206 return new ShaderGL();
207
208 return new ShaderRhi();
209}
210
211#else
212
213QSGMaterialShader* Material::createShader( QSGRendererInterface::RenderMode ) const
214{
215 return new ShaderRhi();
216}
217
218#endif
219
220QSGMaterialType* Material::type() const
221{
222 static QSGMaterialType staticType;
223 return &staticType;
224}
225
226int Material::compare( const QSGMaterial* other ) const
227{
228 auto material = static_cast< const Material* >( other );
229
230 if ( ( material->m_color == m_color )
231 && ( material->m_pixelAlignment == m_pixelAlignment ) )
232 {
233 return 0;
234 }
235
236 return QSGMaterial::compare( other );
237}
238
239class QskBasicLinesNodePrivate final : public QSGGeometryNodePrivate
240{
241 public:
242 QskBasicLinesNodePrivate()
243 : geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
244 {
245 geometry.setDrawingMode( QSGGeometry::DrawLines );
246 }
247
248 QSGGeometry geometry;
249 Material material;
250};
251
252QskBasicLinesNode::QskBasicLinesNode()
253 : QSGGeometryNode( *new QskBasicLinesNodePrivate )
254{
255 Q_D( QskBasicLinesNode );
256
257 setGeometry( &d->geometry );
258 setMaterial( &d->material );
259}
260
261QskBasicLinesNode::~QskBasicLinesNode()
262{
263}
264
265void QskBasicLinesNode::setPixelAlignment( Qt::Orientations orientations )
266{
267 Q_D( QskBasicLinesNode );
268
269 if ( orientations != d->material.m_pixelAlignment )
270 {
271 d->material.m_pixelAlignment = orientations;
272 markDirty( QSGNode::DirtyMaterial );
273 }
274}
275
276Qt::Orientations QskBasicLinesNode::pixelAlignment() const
277{
278 return d_func()->material.m_pixelAlignment;
279}
280
281void QskBasicLinesNode::setColor( const QColor& color )
282{
283 Q_D( QskBasicLinesNode );
284
285 const auto c = color.toRgb();
286 if ( c != d->material.m_color )
287 {
288 d->material.m_color = c;
289 markDirty( QSGNode::DirtyMaterial );
290 }
291}
292
293QColor QskBasicLinesNode::color() const
294{
295 return d_func()->material.m_color;
296}
297
298void QskBasicLinesNode::setLineWidth( float lineWidth )
299{
300 Q_D( QskBasicLinesNode );
301
302 lineWidth = std::max( lineWidth, 0.0f );
303 if( lineWidth != d->geometry.lineWidth() )
304 d->geometry.setLineWidth( lineWidth );
305}
306
307float QskBasicLinesNode::lineWidth() const
308{
309 return d_func()->geometry.lineWidth();
310}
311