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 | #include "qsgtexturematerial_p.h" |
5 | #include <private/qsgtexture_p.h> |
6 | #include <rhi/qrhi.h> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | inline static bool isPowerOfTwo(int x) |
11 | { |
12 | // Assumption: x >= 1 |
13 | return x == (x & -x); |
14 | } |
15 | |
16 | QSGOpaqueTextureMaterialRhiShader::QSGOpaqueTextureMaterialRhiShader() |
17 | { |
18 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/opaquetexture.vert.qsb" )); |
19 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/opaquetexture.frag.qsb" )); |
20 | } |
21 | |
22 | bool QSGOpaqueTextureMaterialRhiShader::updateUniformData(RenderState &state, QSGMaterial *, QSGMaterial *) |
23 | { |
24 | bool changed = false; |
25 | QByteArray *buf = state.uniformData(); |
26 | |
27 | if (state.isMatrixDirty()) { |
28 | const QMatrix4x4 m = state.combinedMatrix(); |
29 | memcpy(dest: buf->data(), src: m.constData(), n: 64); |
30 | changed = true; |
31 | } |
32 | |
33 | return changed; |
34 | } |
35 | |
36 | void QSGOpaqueTextureMaterialRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture, |
37 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
38 | { |
39 | if (binding != 1) |
40 | return; |
41 | |
42 | #ifdef QT_NO_DEBUG |
43 | Q_UNUSED(oldMaterial); |
44 | #endif |
45 | Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type()); |
46 | QSGOpaqueTextureMaterial *tx = static_cast<QSGOpaqueTextureMaterial *>(newMaterial); |
47 | QSGTexture *t = tx->texture(); |
48 | if (!t) { |
49 | *texture = nullptr; |
50 | return; |
51 | } |
52 | |
53 | t->setFiltering(tx->filtering()); |
54 | t->setMipmapFiltering(tx->mipmapFiltering()); |
55 | t->setAnisotropyLevel(tx->anisotropyLevel()); |
56 | |
57 | t->setHorizontalWrapMode(tx->horizontalWrapMode()); |
58 | t->setVerticalWrapMode(tx->verticalWrapMode()); |
59 | if (!state.rhi()->isFeatureSupported(feature: QRhi::NPOTTextureRepeat)) { |
60 | QSize size = t->textureSize(); |
61 | const bool isNpot = !isPowerOfTwo(x: size.width()) || !isPowerOfTwo(x: size.height()); |
62 | if (isNpot) { |
63 | t->setHorizontalWrapMode(QSGTexture::ClampToEdge); |
64 | t->setVerticalWrapMode(QSGTexture::ClampToEdge); |
65 | t->setMipmapFiltering(QSGTexture::None); |
66 | } |
67 | } |
68 | |
69 | t->commitTextureOperations(rhi: state.rhi(), resourceUpdates: state.resourceUpdateBatch()); |
70 | *texture = t; |
71 | } |
72 | |
73 | |
74 | /*! |
75 | \class QSGOpaqueTextureMaterial |
76 | \brief The QSGOpaqueTextureMaterial class provides a convenient way of |
77 | rendering textured geometry in the scene graph. |
78 | \inmodule QtQuick |
79 | \ingroup qtquick-scenegraph-materials |
80 | |
81 | \warning This utility class is only functional when running with the |
82 | default backend of the Qt Quick scenegraph. |
83 | |
84 | The opaque textured material will fill every pixel in a geometry with |
85 | the supplied texture. The material does not respect the opacity of the |
86 | QSGMaterialShader::RenderState, so opacity nodes in the parent chain |
87 | of nodes using this material, have no effect. |
88 | |
89 | The geometry to be rendered with an opaque texture material requires |
90 | vertices in attribute location 0 and texture coordinates in attribute |
91 | location 1. The texture coordinate is a 2-dimensional floating-point |
92 | tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an |
93 | attribute set compatible with this material. |
94 | |
95 | The texture to be rendered can be set using setTexture(). How the |
96 | texture should be rendered can be specified using setMipmapFiltering(), |
97 | setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode(). |
98 | The rendering state is set on the texture instance just before it |
99 | is bound. |
100 | |
101 | The opaque textured material respects the current matrix and the alpha |
102 | channel of the texture. It will disregard the accumulated opacity in |
103 | the scenegraph. |
104 | |
105 | A texture material must have a texture set before it is used as |
106 | a material in the scene graph. |
107 | */ |
108 | |
109 | |
110 | |
111 | /*! |
112 | Creates a new QSGOpaqueTextureMaterial. |
113 | |
114 | The default mipmap filtering and filtering mode is set to |
115 | QSGTexture::Nearest. The default wrap modes is set to |
116 | \c QSGTexture::ClampToEdge. |
117 | |
118 | */ |
119 | QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial() |
120 | : m_texture(nullptr) |
121 | , m_filtering(QSGTexture::Nearest) |
122 | , m_mipmap_filtering(QSGTexture::None) |
123 | , m_horizontal_wrap(QSGTexture::ClampToEdge) |
124 | , m_vertical_wrap(QSGTexture::ClampToEdge) |
125 | , m_anisotropy_level(QSGTexture::AnisotropyNone) |
126 | { |
127 | } |
128 | |
129 | |
130 | /*! |
131 | \internal |
132 | */ |
133 | QSGMaterialType *QSGOpaqueTextureMaterial::type() const |
134 | { |
135 | static QSGMaterialType type; |
136 | return &type; |
137 | } |
138 | |
139 | /*! |
140 | \internal |
141 | */ |
142 | QSGMaterialShader *QSGOpaqueTextureMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const |
143 | { |
144 | Q_UNUSED(renderMode); |
145 | return new QSGOpaqueTextureMaterialRhiShader; |
146 | } |
147 | |
148 | |
149 | /*! |
150 | \fn QSGTexture *QSGOpaqueTextureMaterial::texture() const |
151 | |
152 | Returns this texture material's texture. |
153 | */ |
154 | |
155 | |
156 | |
157 | /*! |
158 | Sets the texture of this material to \a texture. |
159 | |
160 | The material does not take ownership of the texture. |
161 | */ |
162 | |
163 | void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture) |
164 | { |
165 | m_texture = texture; |
166 | setFlag(flags: Blending, on: m_texture ? m_texture->hasAlphaChannel() : false); |
167 | } |
168 | |
169 | |
170 | |
171 | /*! |
172 | \fn void QSGOpaqueTextureMaterial::setMipmapFiltering(QSGTexture::Filtering filtering) |
173 | |
174 | Sets the mipmap mode to \a filtering. |
175 | |
176 | The mipmap filtering mode is set on the texture instance just before the |
177 | texture is bound for rendering. |
178 | |
179 | If the texture does not have mipmapping support, enabling mipmapping has no |
180 | effect. |
181 | */ |
182 | |
183 | |
184 | |
185 | /*! |
186 | \fn QSGTexture::Filtering QSGOpaqueTextureMaterial::mipmapFiltering() const |
187 | |
188 | Returns this material's mipmap filtering mode. |
189 | |
190 | The default mipmap mode is \c QSGTexture::Nearest. |
191 | */ |
192 | |
193 | |
194 | |
195 | /*! |
196 | \fn void QSGOpaqueTextureMaterial::setFiltering(QSGTexture::Filtering filtering) |
197 | |
198 | Sets the filtering to \a filtering. |
199 | |
200 | The filtering mode is set on the texture instance just before the texture |
201 | is bound for rendering. |
202 | */ |
203 | |
204 | |
205 | |
206 | /*! |
207 | \fn QSGTexture::Filtering QSGOpaqueTextureMaterial::filtering() const |
208 | |
209 | Returns this material's filtering mode. |
210 | |
211 | The default filtering is \c QSGTexture::Nearest. |
212 | */ |
213 | |
214 | |
215 | |
216 | /*! |
217 | \fn void QSGOpaqueTextureMaterial::setHorizontalWrapMode(QSGTexture::WrapMode mode) |
218 | |
219 | Sets the horizontal wrap mode to \a mode. |
220 | |
221 | The horizontal wrap mode is set on the texture instance just before the texture |
222 | is bound for rendering. |
223 | */ |
224 | |
225 | |
226 | |
227 | /*! |
228 | \fn QSGTexture::WrapMode QSGOpaqueTextureMaterial::horizontalWrapMode() const |
229 | |
230 | Returns this material's horizontal wrap mode. |
231 | |
232 | The default horizontal wrap mode is \c QSGTexture::ClampToEdge. |
233 | */ |
234 | |
235 | |
236 | |
237 | /*! |
238 | \fn void QSGOpaqueTextureMaterial::setVerticalWrapMode(QSGTexture::WrapMode mode) |
239 | |
240 | Sets the vertical wrap mode to \a mode. |
241 | |
242 | The vertical wrap mode is set on the texture instance just before the texture |
243 | is bound for rendering. |
244 | */ |
245 | |
246 | |
247 | |
248 | /*! |
249 | \fn QSGTexture::WrapMode QSGOpaqueTextureMaterial::verticalWrapMode() const |
250 | |
251 | Returns this material's vertical wrap mode. |
252 | |
253 | The default vertical wrap mode is \c QSGTexture::ClampToEdge. |
254 | */ |
255 | |
256 | /*! |
257 | \fn void QSGOpaqueTextureMaterial::setAnisotropyLevel(QSGTexture::AnisotropyLevel level) |
258 | |
259 | Sets this material's anistropy level to \a level. |
260 | */ |
261 | |
262 | /*! |
263 | \fn QSGTexture::AnisotropyLevel QSGOpaqueTextureMaterial::anisotropyLevel() const |
264 | |
265 | Returns this material's anistropy level. |
266 | */ |
267 | |
268 | /*! |
269 | \internal |
270 | */ |
271 | |
272 | int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const |
273 | { |
274 | Q_ASSERT(o && type() == o->type()); |
275 | const QSGOpaqueTextureMaterial *other = static_cast<const QSGOpaqueTextureMaterial *>(o); |
276 | Q_ASSERT(m_texture); |
277 | Q_ASSERT(other->texture()); |
278 | const qint64 diff = m_texture->comparisonKey() - other->texture()->comparisonKey(); |
279 | if (diff != 0) |
280 | return diff < 0 ? -1 : 1; |
281 | return int(m_filtering) - int(other->m_filtering); |
282 | } |
283 | |
284 | |
285 | |
286 | /*! |
287 | \class QSGTextureMaterial |
288 | \brief The QSGTextureMaterial class provides a convenient way of |
289 | rendering textured geometry in the scene graph. |
290 | \inmodule QtQuick |
291 | \ingroup qtquick-scenegraph-materials |
292 | |
293 | \warning This utility class is only functional when running with the |
294 | default backend of the Qt Quick scenegraph. |
295 | |
296 | The textured material will fill every pixel in a geometry with |
297 | the supplied texture. |
298 | |
299 | The geometry to be rendered with a texture material requires |
300 | vertices in attribute location 0 and texture coordinates in attribute |
301 | location 1. The texture coordinate is a 2-dimensional floating-point |
302 | tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an |
303 | attribute set compatible with this material. |
304 | |
305 | The texture to be rendered can be set using setTexture(). How the |
306 | texture should be rendered can be specified using setMipmapFiltering(), |
307 | setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode(). |
308 | The rendering state is set on the texture instance just before it |
309 | is bound. |
310 | |
311 | The textured material respects the current matrix and the alpha |
312 | channel of the texture. It will also respect the accumulated opacity |
313 | in the scenegraph. |
314 | |
315 | A texture material must have a texture set before it is used as |
316 | a material in the scene graph. |
317 | */ |
318 | |
319 | /*! |
320 | \internal |
321 | */ |
322 | |
323 | QSGMaterialType *QSGTextureMaterial::type() const |
324 | { |
325 | static QSGMaterialType type; |
326 | return &type; |
327 | } |
328 | |
329 | /*! |
330 | \internal |
331 | */ |
332 | |
333 | QSGMaterialShader *QSGTextureMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const |
334 | { |
335 | Q_UNUSED(renderMode); |
336 | return new QSGTextureMaterialRhiShader; |
337 | } |
338 | |
339 | |
340 | QSGTextureMaterialRhiShader::QSGTextureMaterialRhiShader() |
341 | { |
342 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/texture.vert.qsb" )); |
343 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/texture.frag.qsb" )); |
344 | } |
345 | |
346 | bool QSGTextureMaterialRhiShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
347 | { |
348 | bool changed = false; |
349 | QByteArray *buf = state.uniformData(); |
350 | |
351 | if (state.isOpacityDirty()) { |
352 | const float opacity = state.opacity(); |
353 | memcpy(dest: buf->data() + 64, src: &opacity, n: 4); |
354 | changed = true; |
355 | } |
356 | |
357 | changed |= QSGOpaqueTextureMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial); |
358 | |
359 | return changed; |
360 | } |
361 | |
362 | QT_END_NAMESPACE |
363 | |