1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | |
5 | #include "qsgsimpletexturenode.h" |
6 | #include <private/qsgnode_p.h> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | class QSGSimpleTextureNodePrivate : public QSGGeometryNodePrivate |
11 | { |
12 | public: |
13 | QSGSimpleTextureNodePrivate() |
14 | : texCoordMode(QSGSimpleTextureNode::NoTransform) |
15 | , isAtlasTexture(false) |
16 | , ownsTexture(false) |
17 | {} |
18 | |
19 | QRectF sourceRect; |
20 | QSGSimpleTextureNode::TextureCoordinatesTransformMode texCoordMode; |
21 | uint isAtlasTexture : 1; |
22 | uint ownsTexture : 1; |
23 | }; |
24 | |
25 | static void qsgsimpletexturenode_update(QSGGeometry *g, |
26 | QSGTexture *texture, |
27 | const QRectF &rect, |
28 | QRectF sourceRect, |
29 | QSGSimpleTextureNode::TextureCoordinatesTransformMode texCoordMode) |
30 | { |
31 | if (!texture) |
32 | return; |
33 | |
34 | if (!sourceRect.width() || !sourceRect.height()) { |
35 | QSize ts = texture->textureSize(); |
36 | sourceRect = QRectF(0, 0, ts.width(), ts.height()); |
37 | } |
38 | |
39 | // Maybe transform the texture coordinates |
40 | if (texCoordMode.testFlag(flag: QSGSimpleTextureNode::MirrorHorizontally)) { |
41 | float tmp = sourceRect.left(); |
42 | sourceRect.setLeft(sourceRect.right()); |
43 | sourceRect.setRight(tmp); |
44 | } |
45 | if (texCoordMode.testFlag(flag: QSGSimpleTextureNode::MirrorVertically)) { |
46 | float tmp = sourceRect.top(); |
47 | sourceRect.setTop(sourceRect.bottom()); |
48 | sourceRect.setBottom(tmp); |
49 | } |
50 | |
51 | QSGGeometry::updateTexturedRectGeometry(g, rect, sourceRect: texture->convertToNormalizedSourceRect(rect: sourceRect)); |
52 | } |
53 | |
54 | /*! |
55 | \class QSGSimpleTextureNode |
56 | \brief The QSGSimpleTextureNode class is provided for convenience to easily draw |
57 | textured content using the QML scene graph. |
58 | |
59 | \inmodule QtQuick |
60 | |
61 | \warning The simple texture node class must have a texture before being |
62 | added to the scene graph to be rendered. |
63 | |
64 | \warning This utility class is only functional when running with the default |
65 | or software backends of the Qt Quick scenegraph. As an alternative, prefer |
66 | using QSGImageNode via QQuickWindow::createImageNode(). However, this |
67 | standalone class is still useful when used via subclassing and the |
68 | application knows that no special scenegraph backends will be involved. |
69 | */ |
70 | |
71 | /*! |
72 | Constructs a new simple texture node |
73 | */ |
74 | QSGSimpleTextureNode::QSGSimpleTextureNode() |
75 | : QSGGeometryNode(*new QSGSimpleTextureNodePrivate) |
76 | , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) |
77 | { |
78 | setGeometry(&m_geometry); |
79 | setMaterial(&m_material); |
80 | setOpaqueMaterial(&m_opaque_material); |
81 | m_material.setMipmapFiltering(QSGTexture::None); |
82 | m_opaque_material.setMipmapFiltering(QSGTexture::None); |
83 | #ifdef QSG_RUNTIME_DESCRIPTION |
84 | qsgnode_set_description(node: this, description: QLatin1String("simpletexture" )); |
85 | #endif |
86 | } |
87 | |
88 | /*! |
89 | Destroys the texture node |
90 | */ |
91 | QSGSimpleTextureNode::~QSGSimpleTextureNode() |
92 | { |
93 | Q_D(QSGSimpleTextureNode); |
94 | if (d->ownsTexture) |
95 | delete m_material.texture(); |
96 | } |
97 | |
98 | /*! |
99 | Sets the filtering to be used for this texture node to \a filtering. |
100 | |
101 | For smooth scaling, use QSGTexture::Linear; for normal scaling, use |
102 | QSGTexture::Nearest. |
103 | */ |
104 | void QSGSimpleTextureNode::setFiltering(QSGTexture::Filtering filtering) |
105 | { |
106 | if (m_material.filtering() == filtering) |
107 | return; |
108 | |
109 | m_material.setFiltering(filtering); |
110 | m_opaque_material.setFiltering(filtering); |
111 | markDirty(bits: DirtyMaterial); |
112 | } |
113 | |
114 | |
115 | /*! |
116 | Returns the filtering currently set on this texture node |
117 | */ |
118 | QSGTexture::Filtering QSGSimpleTextureNode::filtering() const |
119 | { |
120 | return m_material.filtering(); |
121 | } |
122 | |
123 | |
124 | /*! |
125 | Sets the target rect of this texture node to \a r. |
126 | */ |
127 | void QSGSimpleTextureNode::setRect(const QRectF &r) |
128 | { |
129 | if (m_rect == r) |
130 | return; |
131 | m_rect = r; |
132 | Q_D(QSGSimpleTextureNode); |
133 | qsgsimpletexturenode_update(g: &m_geometry, texture: texture(), rect: m_rect, sourceRect: d->sourceRect, texCoordMode: d->texCoordMode); |
134 | markDirty(bits: DirtyGeometry); |
135 | } |
136 | |
137 | /*! |
138 | \fn void QSGSimpleTextureNode::setRect(qreal x, qreal y, qreal w, qreal h) |
139 | \overload |
140 | |
141 | Sets the rectangle of this texture node to begin at (\a x, \a y) and have |
142 | width \a w and height \a h. |
143 | */ |
144 | |
145 | /*! |
146 | Returns the target rect of this texture node. |
147 | */ |
148 | QRectF QSGSimpleTextureNode::rect() const |
149 | { |
150 | return m_rect; |
151 | } |
152 | |
153 | /*! |
154 | Sets the source rect of this texture node to \a r. |
155 | |
156 | \since 5.5 |
157 | */ |
158 | void QSGSimpleTextureNode::setSourceRect(const QRectF &r) |
159 | { |
160 | Q_D(QSGSimpleTextureNode); |
161 | if (d->sourceRect == r) |
162 | return; |
163 | d->sourceRect = r; |
164 | qsgsimpletexturenode_update(g: &m_geometry, texture: texture(), rect: m_rect, sourceRect: d->sourceRect, texCoordMode: d->texCoordMode); |
165 | markDirty(bits: DirtyGeometry); |
166 | } |
167 | |
168 | /*! |
169 | \fn void QSGSimpleTextureNode::setSourceRect(qreal x, qreal y, qreal w, qreal h) |
170 | \overload |
171 | \since 5.5 |
172 | |
173 | Sets the rectangle of this texture node to show its texture from (\a x, \a y) and |
174 | have width \a w and height \a h relatively to the QSGTexture::textureSize. |
175 | */ |
176 | |
177 | /*! |
178 | Returns the source rect of this texture node. |
179 | |
180 | \since 5.5 |
181 | */ |
182 | QRectF QSGSimpleTextureNode::sourceRect() const |
183 | { |
184 | Q_D(const QSGSimpleTextureNode); |
185 | return d->sourceRect; |
186 | } |
187 | |
188 | /*! |
189 | Sets the texture of this texture node to \a texture. |
190 | |
191 | Use setOwnsTexture() to set whether the node should take |
192 | ownership of the texture. By default, the node does not |
193 | take ownership. |
194 | |
195 | \warning A texture node must have a texture before being added |
196 | to the scenegraph to be rendered. |
197 | */ |
198 | void QSGSimpleTextureNode::setTexture(QSGTexture *texture) |
199 | { |
200 | Q_ASSERT(texture); |
201 | Q_D(QSGSimpleTextureNode); |
202 | if (d->ownsTexture) |
203 | delete m_material.texture(); |
204 | m_material.setTexture(texture); |
205 | m_opaque_material.setTexture(texture); |
206 | qsgsimpletexturenode_update(g: &m_geometry, texture, rect: m_rect, sourceRect: d->sourceRect, texCoordMode: d->texCoordMode); |
207 | |
208 | DirtyState dirty = DirtyMaterial; |
209 | // It would be tempting to skip the extra bit here and instead use |
210 | // m_material.texture to get the old state, but that texture could |
211 | // have been deleted in the mean time. |
212 | bool wasAtlas = d->isAtlasTexture; |
213 | d->isAtlasTexture = texture->isAtlasTexture(); |
214 | if (wasAtlas || d->isAtlasTexture) |
215 | dirty |= DirtyGeometry; |
216 | markDirty(bits: dirty); |
217 | } |
218 | |
219 | |
220 | |
221 | /*! |
222 | Returns the texture for this texture node |
223 | */ |
224 | QSGTexture *QSGSimpleTextureNode::texture() const |
225 | { |
226 | return m_material.texture(); |
227 | } |
228 | |
229 | /*! |
230 | \enum QSGSimpleTextureNode::TextureCoordinatesTransformFlag |
231 | |
232 | The TextureCoordinatesTransformFlag enum is used to specify the |
233 | mode used to generate texture coordinates for a textured quad. |
234 | |
235 | \value NoTransform Texture coordinates are oriented with window coordinates |
236 | i.e. with origin at top-left. |
237 | |
238 | \value MirrorHorizontally Texture coordinates are inverted in the horizontal axis with |
239 | respect to window coordinates |
240 | |
241 | \value MirrorVertically Texture coordinates are inverted in the vertical axis with |
242 | respect to window coordinates |
243 | */ |
244 | |
245 | /*! |
246 | Sets the method used to generate texture coordinates to \a mode. This can be used to obtain |
247 | correct orientation of the texture. This is commonly needed when using a third party OpenGL |
248 | library to render to texture as OpenGL has an inverted y-axis relative to Qt Quick. |
249 | |
250 | \sa textureCoordinatesTransform() |
251 | */ |
252 | void QSGSimpleTextureNode::setTextureCoordinatesTransform(QSGSimpleTextureNode::TextureCoordinatesTransformMode mode) |
253 | { |
254 | Q_D(QSGSimpleTextureNode); |
255 | if (d->texCoordMode == mode) |
256 | return; |
257 | d->texCoordMode = mode; |
258 | qsgsimpletexturenode_update(g: &m_geometry, texture: texture(), rect: m_rect, sourceRect: d->sourceRect, texCoordMode: d->texCoordMode); |
259 | markDirty(bits: DirtyGeometry | DirtyMaterial); |
260 | } |
261 | |
262 | /*! |
263 | Returns the mode used to generate texture coordinates for this node. |
264 | |
265 | \sa setTextureCoordinatesTransform() |
266 | */ |
267 | QSGSimpleTextureNode::TextureCoordinatesTransformMode QSGSimpleTextureNode::textureCoordinatesTransform() const |
268 | { |
269 | Q_D(const QSGSimpleTextureNode); |
270 | return d->texCoordMode; |
271 | } |
272 | |
273 | /*! |
274 | Sets whether the node takes ownership of the texture to \a owns. |
275 | |
276 | By default, the node does not take ownership of the texture. |
277 | |
278 | \sa setTexture() |
279 | |
280 | \since 5.4 |
281 | */ |
282 | void QSGSimpleTextureNode::setOwnsTexture(bool owns) |
283 | { |
284 | Q_D(QSGSimpleTextureNode); |
285 | d->ownsTexture = owns; |
286 | } |
287 | |
288 | /*! |
289 | Returns \c true if the node takes ownership of the texture; otherwise returns \c false. |
290 | |
291 | \since 5.4 |
292 | */ |
293 | bool QSGSimpleTextureNode::ownsTexture() const |
294 | { |
295 | Q_D(const QSGSimpleTextureNode); |
296 | return d->ownsTexture; |
297 | } |
298 | |
299 | QT_END_NAMESPACE |
300 | |