QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskPaintedNode.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskPaintedNode.h"
7#include "QskSGNode.h"
8#include "QskTextureRenderer.h"
9
10#include <qsgimagenode.h>
11#include <qquickwindow.h>
12#include <qimage.h>
13#include <qpainter.h>
14
15QSK_QT_PRIVATE_BEGIN
16#include <private/qsgplaintexture_p.h>
17QSK_QT_PRIVATE_END
18
19static inline QSGImageNode::TextureCoordinatesTransformMode
20 qskEffectiveTransformMode( const Qt::Orientations mirrored )
21{
22 QSGImageNode::TextureCoordinatesTransformMode mode;
23
24 if ( mirrored & Qt::Vertical )
25 mode |= QSGImageNode::MirrorVertically;
26
27 if ( mirrored & Qt::Horizontal )
28 mode |= QSGImageNode::MirrorHorizontally;
29
30 return mode;
31}
32
33namespace
34{
35 const quint8 imageRole = 250; // reserved for internal use
36
37 inline QSGImageNode* findImageNode( const QSGNode* parentNode )
38 {
39 auto node = QskSGNode::findChildNode(
40 const_cast< QSGNode* >( parentNode ), imageRole );
41
42 return static_cast< QSGImageNode* >( node );
43 }
44}
45
46QskPaintedNode::QskPaintedNode()
47{
48}
49
50QskPaintedNode::~QskPaintedNode()
51{
52}
53
54void QskPaintedNode::setRenderHint( RenderHint renderHint )
55{
56 m_renderHint = renderHint;
57}
58
59QskPaintedNode::RenderHint QskPaintedNode::renderHint() const
60{
61 return m_renderHint;
62}
63
64void QskPaintedNode::setMirrored( Qt::Orientations orientations )
65{
66 if ( orientations != m_mirrored )
67 {
68 m_mirrored = orientations;
69
70 if ( auto imageNode = findImageNode( this ) )
71 {
72 imageNode->setTextureCoordinatesTransform(
73 qskEffectiveTransformMode( orientations ) );
74 }
75 }
76}
77
78Qt::Orientations QskPaintedNode::mirrored() const
79{
80 return m_mirrored;
81}
82
83QSize QskPaintedNode::textureSize() const
84{
85 if ( const auto imageNode = findImageNode( this ) )
86 {
87 if ( auto texture = imageNode->texture() )
88 return texture->textureSize();
89 }
90
91 return QSize();
92}
93
94QRectF QskPaintedNode::rect() const
95{
96 const auto imageNode = findImageNode( this );
97 return imageNode ? imageNode->rect() : QRectF();
98}
99
100void QskPaintedNode::update( QQuickWindow* window,
101 const QRectF& rect, const QSizeF& size, const void* nodeData )
102{
103 auto imageNode = findImageNode( this );
104
105 if ( rect.isEmpty() )
106 {
107 if ( imageNode )
108 {
109 removeChildNode( imageNode );
110 delete imageNode;
111 }
112
113 return;
114 }
115
116 if ( imageNode == nullptr )
117 {
118 imageNode = window->createImageNode();
119
120 imageNode->setOwnsTexture( true );
121 QskSGNode::setNodeRole( imageNode, imageRole );
122
123 appendChildNode( imageNode );
124 }
125
126 QSize imageSize;
127
128 {
129 auto scaledSize = size.isEmpty() ? rect.size() : size;
130 scaledSize *= window->effectiveDevicePixelRatio();
131
132 imageSize = scaledSize.toSize();
133 }
134
135 bool isTextureDirty = false;
136
137 const auto newHash = hash( nodeData );
138 if ( ( newHash == 0 ) || ( newHash != m_hash ) )
139 {
140 m_hash = newHash;
141 isTextureDirty = true;
142 }
143 else
144 {
145 isTextureDirty = ( imageSize != textureSize() );
146 }
147
148
149 if ( isTextureDirty )
150 updateTexture( window, imageSize, nodeData );
151
152 imageNode->setRect( rect );
153 imageNode->setTextureCoordinatesTransform(
154 qskEffectiveTransformMode( m_mirrored ) );
155}
156
157void QskPaintedNode::updateTexture( QQuickWindow* window,
158 const QSize& size, const void* nodeData )
159{
160 auto imageNode = findImageNode( this );
161
162 if ( ( m_renderHint == OpenGL ) && QskTextureRenderer::isOpenGLWindow( window ) )
163 {
164 const auto textureId = createTextureGL( window, size, nodeData );
165
166 auto texture = qobject_cast< QSGPlainTexture* >( imageNode->texture() );
167 if ( texture == nullptr )
168 {
169 texture = new QSGPlainTexture;
170 texture->setHasAlphaChannel( true );
171 texture->setOwnsTexture( true );
172
173 imageNode->setTexture( texture );
174 }
175
176 QskTextureRenderer::setTextureId( window, textureId, size, texture );
177 }
178 else
179 {
180 const auto image = createImage( window, size, nodeData );
181
182 if ( auto texture = qobject_cast< QSGPlainTexture* >( imageNode->texture() ) )
183 texture->setImage( image );
184 else
185 imageNode->setTexture( window->createTextureFromImage( image ) );
186 }
187}
188
189QImage QskPaintedNode::createImage( QQuickWindow* window,
190 const QSize& size, const void* nodeData )
191{
192 QImage image( size, QImage::Format_RGBA8888_Premultiplied );
193 image.fill( Qt::transparent );
194
195 QPainter painter( &image );
196
197 /*
198 setting a devicePixelRatio for the image only works for
199 value >= 1.0. So we have to scale manually.
200 */
201 const auto ratio = window->effectiveDevicePixelRatio();
202 painter.scale( ratio, ratio );
203
204 paint( &painter, size / ratio, nodeData );
205
206 painter.end();
207
208 return image;
209}
210
211quint32 QskPaintedNode::createTextureGL(
212 QQuickWindow* window, const QSize& size, const void* nodeData )
213{
214 class PaintHelper : public QskTextureRenderer::PaintHelper
215 {
216 public:
217 PaintHelper( QskPaintedNode* node, const void* nodeData )
218 : m_node( node )
219 , m_nodeData( nodeData )
220 {
221 }
222
223 void paint( QPainter* painter, const QSize& size ) override
224 {
225 m_node->paint( painter, size, m_nodeData );
226 }
227
228 private:
229 QskPaintedNode* m_node;
230 const void* m_nodeData;
231 };
232
233 PaintHelper helper( this, nodeData );
234 return createPaintedTextureGL( window, size, &helper );
235}