1 | // Copyright (C) 2020 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qquick3dshaderutils_p.h" |
5 | |
6 | #include <QtCore/qfile.h> |
7 | #include <QtQml/qqmlcontext.h> |
8 | #include <QtQml/qqmlfile.h> |
9 | |
10 | #include "qquick3dviewport_p.h" |
11 | #include "qquick3dcustommaterial_p.h" |
12 | #include "qquick3deffect_p.h" |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | /*! |
17 | \qmltype Shader |
18 | \inherits Object |
19 | \inqmlmodule QtQuick3D |
20 | \brief Container component for defining shader code used by post-processing effects. |
21 | |
22 | The Shader type is used for populating the \l{Pass::shaders}{shaders} list in the |
23 | render \l{Pass}{pass} of an \l Effect. |
24 | |
25 | A shader is code which is executed directly on the graphic hardware at a particular |
26 | \l{Shader::stage}{stage} of the rendering pipeline. |
27 | |
28 | \sa Effect |
29 | */ |
30 | /*! |
31 | \qmlproperty url Shader::shader |
32 | Specifies the name of the shader source file. For details on how to write shader code, |
33 | see the \l Effect documentation. |
34 | */ |
35 | /*! |
36 | \qmlproperty enumeration Shader::stage |
37 | Specifies the stage of the rendering pipeline when the shader code will be executed. |
38 | The default is \c Shader.Fragment |
39 | |
40 | \value Shader.Vertex The shader is a vertex shader. This code is run once per vertex |
41 | in the input geometry and can be used to modify it before the geometry is rasterized |
42 | (scan converted). In the case of effects, the input geometry is always a quad (four |
43 | vertexes representing the corners of the render target). |
44 | \value Shader.Fragment The shader is a fragment shader. After vertex processing, |
45 | the modified geometry is turned into fragments (rasterization). Then a fragment shader |
46 | is executed for each fragment, assigning a color to it. Fragments are a related concept |
47 | to pixels, but with additional information attached. Also, as a result of some |
48 | anti-aliasing strategies, there may be more than one fragment for each pixel in the |
49 | output. |
50 | */ |
51 | |
52 | /*! |
53 | \qmltype TextureInput |
54 | \inherits Object |
55 | \inqmlmodule QtQuick3D |
56 | \brief Specifies a texture exposed to the shaders of a CustomMaterial or Effect. |
57 | |
58 | This is a type which can be used for exposing a \l Texture to a shader, either |
59 | in the \l{Pass}{render pass} of an \l Effect, or in a \l CustomMaterial. It exists |
60 | primarily to assign a local name to the \l Texture that can be referenced from |
61 | shaders. |
62 | |
63 | When a TextureInput property is declared in an \l Effect or a \l CustomMaterial, |
64 | it will automatically be available as a sampler in all shaders by its property |
65 | name. |
66 | */ |
67 | /*! |
68 | \qmlproperty Texture TextureInput::texture |
69 | The texture for which this TextureInput serves as an indirection. |
70 | */ |
71 | /*! |
72 | \qmlproperty bool TextureInput::enabled |
73 | The property determines if this TextureInput is enabled. The default value |
74 | is true. When disabled, the shaders of the effect sample a dummy, opaque |
75 | black texture instead of the one specified by \l texture. |
76 | */ |
77 | |
78 | /*! |
79 | \qmltype Pass |
80 | \inherits Object |
81 | \inqmlmodule QtQuick3D |
82 | \brief Defines a render pass in an Effect. |
83 | |
84 | An \l Effect may consist of multiple render passes. Each render pass has a |
85 | setup phase where the list of \l{Pass::commands}{render commands} are executed, |
86 | a \l{Pass::output}{output buffer} and a list of \l{Pass::shaders}{shaders} to |
87 | use for rendering the effect. |
88 | |
89 | See the documentation for \l Effect for more details on how to set up multiple |
90 | rendering passes. |
91 | */ |
92 | /*! |
93 | \qmlproperty Buffer Pass::output |
94 | Specifies the output \l {Buffer}{buffer} of the pass. |
95 | */ |
96 | /*! |
97 | \qmlproperty list Pass::commands |
98 | Specifies the list of render \l {Command}{commands} of the pass. |
99 | */ |
100 | /*! |
101 | \qmlproperty list Pass::shaders |
102 | Specifies the list of \l {Shader}{shaders} of the pass. |
103 | */ |
104 | |
105 | /*! |
106 | \qmltype Command |
107 | \inherits Object |
108 | \inqmlmodule QtQuick3D |
109 | \brief Supertype of commands to be performed as part of a pass in an Effect. |
110 | |
111 | The Command type should not be instantiated by itself, but only exists as a |
112 | polymorphic supertype for the different actions that can be performed as part |
113 | of a \l{Pass}{render pass}. |
114 | |
115 | \sa BufferInput, SetUniformValue, Effect |
116 | */ |
117 | |
118 | /*! |
119 | \qmltype BufferInput |
120 | \inherits Command |
121 | \inqmlmodule QtQuick3D |
122 | \brief Defines an input buffer to be used as input for a pass of an Effect. |
123 | |
124 | BufferInput is a \l Command which can be added to the list of commands in the \l Pass of |
125 | an \l Effect. When executed, it will expose the buffer as a sample to the shaders |
126 | in the render pass. The shaders must declare a sampler with the name given in the |
127 | BufferInput's \c sampler property. |
128 | |
129 | This can be used for sharing intermediate results between the different passes of an |
130 | effect. |
131 | |
132 | \sa TextureInput |
133 | */ |
134 | /*! |
135 | \qmlproperty Buffer BufferInput::buffer |
136 | Specifies the \l {Buffer}{buffer} which should be exposed to the shader. |
137 | */ |
138 | /*! |
139 | \qmlproperty string BufferInput::sampler |
140 | Specifies the name under which the buffer is exposed to the shader. |
141 | When this property is not set, the buffer is exposed with the built-in name \c INPUT. |
142 | */ |
143 | |
144 | /*! |
145 | \qmltype Buffer |
146 | \inherits Object |
147 | \inqmlmodule QtQuick3D |
148 | \brief Creates or references a color buffer to be used for a pass of an Effect. |
149 | |
150 | A Buffer can be used to create intermediate buffers to share data between |
151 | \l{Pass}{render passes} in an \l Effect. |
152 | |
153 | \note If the \l name property of the Buffer is empty, it will reference the |
154 | default output texture of the render pass. |
155 | */ |
156 | /*! |
157 | \qmlproperty enumeration Buffer::format |
158 | Specifies the texture format. The default value is Buffer.RGBA8. |
159 | |
160 | \value Buffer.RGBA8 |
161 | \value Buffer.RGBA16F |
162 | \value Buffer.RGBA32F |
163 | \value Buffer.R8 |
164 | \value Buffer.R16 |
165 | \value Buffer.R16F |
166 | \value Buffer.R32F |
167 | */ |
168 | /*! |
169 | \qmlproperty enumeration Buffer::textureFilterOperation |
170 | Specifies the texture filtering mode when sampling the contents of the |
171 | Buffer. The default value is Buffer.Linear. |
172 | |
173 | \value Buffer.Nearest Use nearest-neighbor filtering. |
174 | \value Buffer.Linear Use linear filtering. |
175 | */ |
176 | /*! |
177 | \qmlproperty enumeration Buffer::textureCoordOperation |
178 | Specifies the behavior for texture coordinates when sampling outside the [0, 1] range. |
179 | The default is Buffer.ClampToEdge. |
180 | |
181 | \value Buffer.ClampToEdge Clamp coordinates to the edges. |
182 | \value Buffer.Repeat Wrap the coordinates at the edges to tile the texture. |
183 | \value Buffer.MirroredRepeat Wrap the coordinate at the edges, but mirror the texture |
184 | when tiling it. |
185 | */ |
186 | /*! |
187 | \qmlproperty real Buffer::sizeMultiplier |
188 | Specifies the size multiplier of the buffer. For instance, a value of \c 1.0 creates |
189 | a buffer with the same size as the effect's input texture while \c 0.5 creates buffer |
190 | where both width and height is half as big. The default value is 1.0. |
191 | */ |
192 | /*! |
193 | \qmlproperty enumeration Buffer::bufferFlags |
194 | Specifies the buffer allocation flags. The default is Buffer.None. |
195 | |
196 | \value Buffer.None No special behavior. |
197 | \value Buffer.SceneLifetime The buffer is allocated for the whole lifetime of the scene. |
198 | */ |
199 | /*! |
200 | \qmlproperty string Buffer::name |
201 | Specifies the name of the buffer. |
202 | |
203 | \note When this property is empty, the Buffer will refer to the default output texture |
204 | of the \l{Pass}{render pass} instead of allocating a buffer. This can be useful to |
205 | override certain settings of the output, such as the texture format, without introducing |
206 | a new, separate intermediate texture. |
207 | */ |
208 | |
209 | /*! |
210 | \qmltype SetUniformValue |
211 | \inherits Command |
212 | \inqmlmodule QtQuick3D |
213 | \brief Defines a value to be set during a single \l {Pass}{pass}. |
214 | \since 5.15 |
215 | |
216 | SetUniformValue is a \l Command which can be added to the list of commands in a \l Pass. When |
217 | executed, it will set the uniform given by the \l{SetUniformValue::target}{target} property |
218 | to \l{SetUniformValue::value}{value}. |
219 | |
220 | \note The value set by this command is will only be set during the \l {Pass}{pass} it occurs in. |
221 | For consecutive passes the value will be revert to the initial value of the uniform as it |
222 | was defined in the \l Effect item. |
223 | |
224 | \sa BufferInput |
225 | */ |
226 | /*! |
227 | \qmlproperty string SetUniformValue::target |
228 | Specifies the name of the uniform that will have its value changed during the \l {Pass}{pass}. |
229 | This must match the name of an existing property in the \l Effect. |
230 | */ |
231 | /*! |
232 | \qmlproperty Variant SetUniformValue::value |
233 | Specifies the value that will be set on the \c target uniform. |
234 | */ |
235 | |
236 | namespace QSSGShaderUtils { |
237 | |
238 | ResolveFunction resolveShaderOverride = nullptr; |
239 | |
240 | void setResolveFunction(ResolveFunction fn) |
241 | { |
242 | resolveShaderOverride = fn; |
243 | } |
244 | |
245 | QByteArray resolveShader(const QUrl &fileUrl, const QQmlContext *context, QByteArray &shaderPathKey) |
246 | { |
247 | if (resolveShaderOverride) { |
248 | QByteArray shaderData; |
249 | if (resolveShaderOverride(fileUrl, context, shaderData, shaderPathKey)) |
250 | return shaderData; |
251 | } |
252 | |
253 | if (!shaderPathKey.isEmpty()) |
254 | shaderPathKey.append(c: '>'); |
255 | |
256 | const QUrl loadUrl = context ? context->resolvedUrl(fileUrl) : fileUrl; |
257 | const QString filePath = QQmlFile::urlToLocalFileOrQrc(loadUrl); |
258 | |
259 | QFile f(filePath); |
260 | if (f.open(flags: QIODevice::ReadOnly | QIODevice::Text)) { |
261 | shaderPathKey += loadUrl.fileName().toUtf8(); |
262 | return f.readAll(); |
263 | } else { |
264 | qWarning(msg: "Failed to read shader code from %s" , qPrintable(filePath)); |
265 | } |
266 | |
267 | return QByteArray(); |
268 | } |
269 | |
270 | // These are the QMetaTypes that we convert into uniforms. |
271 | static constexpr QMetaType::Type qssg_metatype_list[] { |
272 | QMetaType::Double, |
273 | QMetaType::Bool, |
274 | QMetaType::QVector2D, |
275 | QMetaType::QVector3D, |
276 | QMetaType::QVector4D, |
277 | QMetaType::Int, |
278 | QMetaType::QColor, |
279 | QMetaType::QSize, |
280 | QMetaType::QSizeF, |
281 | QMetaType::QPoint, |
282 | QMetaType::QPointF, |
283 | QMetaType::QRect, |
284 | QMetaType::QRectF, |
285 | QMetaType::QQuaternion, |
286 | QMetaType::QMatrix4x4 |
287 | }; |
288 | |
289 | template<> |
290 | struct ShaderType<QMetaType::Double> |
291 | { |
292 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Float; } |
293 | static QByteArray name() { return QByteArrayLiteral("float" ); } |
294 | }; |
295 | |
296 | template<> |
297 | struct ShaderType<QMetaType::Bool> |
298 | { |
299 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Boolean; } |
300 | static QByteArray name() { return QByteArrayLiteral("bool" ); } |
301 | }; |
302 | |
303 | template<> |
304 | struct ShaderType<QMetaType::Int> |
305 | { |
306 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Integer; } |
307 | static QByteArray name() { return QByteArrayLiteral("int" ); } |
308 | }; |
309 | |
310 | template<> |
311 | struct ShaderType<QMetaType::QVector2D> |
312 | { |
313 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Vec2; } |
314 | static QByteArray name() { return QByteArrayLiteral("vec2" ); } |
315 | }; |
316 | |
317 | template<> |
318 | struct ShaderType<QMetaType::QVector3D> |
319 | { |
320 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Vec3; } |
321 | static QByteArray name() { return QByteArrayLiteral("vec3" ); } |
322 | }; |
323 | |
324 | template<> |
325 | struct ShaderType<QMetaType::QVector4D> |
326 | { |
327 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Vec4; } |
328 | static QByteArray name() { return QByteArrayLiteral("vec4" ); } |
329 | }; |
330 | |
331 | template<> |
332 | struct ShaderType<QMetaType::QColor> |
333 | { |
334 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Rgba; } |
335 | static QByteArray name() { return QByteArrayLiteral("vec4" ); } |
336 | }; |
337 | |
338 | template<> |
339 | struct ShaderType<QMetaType::QSize> |
340 | { |
341 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Size; } |
342 | static QByteArray name() { return QByteArrayLiteral("vec2" ); } |
343 | }; |
344 | |
345 | template<> |
346 | struct ShaderType<QMetaType::QSizeF> |
347 | { |
348 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::SizeF; } |
349 | static QByteArray name() { return QByteArrayLiteral("vec2" ); } |
350 | }; |
351 | |
352 | template<> |
353 | struct ShaderType<QMetaType::QPoint> |
354 | { |
355 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Point; } |
356 | static QByteArray name() { return QByteArrayLiteral("vec2" ); } |
357 | }; |
358 | |
359 | template<> |
360 | struct ShaderType<QMetaType::QPointF> |
361 | { |
362 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::PointF; } |
363 | static QByteArray name() { return QByteArrayLiteral("vec2" ); } |
364 | }; |
365 | |
366 | template<> |
367 | struct ShaderType<QMetaType::QRect> |
368 | { |
369 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Rect; } |
370 | static QByteArray name() { return QByteArrayLiteral("vec4" ); } |
371 | }; |
372 | |
373 | template<> |
374 | struct ShaderType<QMetaType::QRectF> |
375 | { |
376 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::RectF; } |
377 | static QByteArray name() { return QByteArrayLiteral("vec4" ); } |
378 | }; |
379 | |
380 | template<> |
381 | struct ShaderType<QMetaType::QQuaternion> |
382 | { |
383 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Quaternion; } |
384 | static QByteArray name() { return QByteArrayLiteral("vec4" ); } |
385 | }; |
386 | |
387 | template<> |
388 | struct ShaderType<QMetaType::QMatrix4x4> |
389 | { |
390 | static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Matrix4x4; } |
391 | static QByteArray name() { return QByteArrayLiteral("mat4" ); } |
392 | }; |
393 | |
394 | QByteArray uniformTypeName(QMetaType type) |
395 | { |
396 | switch (type.id()) { |
397 | case QMetaType::Double: |
398 | case QMetaType::Float: |
399 | return ShaderType<QMetaType::Double>::name(); |
400 | case QMetaType::Bool: |
401 | return ShaderType<QMetaType::Bool>::name(); |
402 | case QMetaType::QVector2D: |
403 | return ShaderType<QMetaType::QVector2D>::name(); |
404 | case QMetaType::QVector3D: |
405 | return ShaderType<QMetaType::QVector3D>::name(); |
406 | case QMetaType::QVector4D: |
407 | return ShaderType<QMetaType::QVector4D>::name(); |
408 | case QMetaType::Int: |
409 | return ShaderType<QMetaType::Int>::name(); |
410 | case QMetaType::QColor: |
411 | return ShaderType<QMetaType::QColor>::name(); |
412 | case QMetaType::QSize: |
413 | return ShaderType<QMetaType::QSize>::name(); |
414 | case QMetaType::QSizeF: |
415 | return ShaderType<QMetaType::QSizeF>::name(); |
416 | case QMetaType::QPoint: |
417 | return ShaderType<QMetaType::QPoint>::name(); |
418 | case QMetaType::QPointF: |
419 | return ShaderType<QMetaType::QPointF>::name(); |
420 | case QMetaType::QRect: |
421 | return ShaderType<QMetaType::QRect>::name(); |
422 | case QMetaType::QRectF: |
423 | return ShaderType<QMetaType::QRectF>::name(); |
424 | case QMetaType::QQuaternion: |
425 | return ShaderType<QMetaType::QQuaternion>::name(); |
426 | case QMetaType::QMatrix4x4: |
427 | return ShaderType<QMetaType::QMatrix4x4>::name(); |
428 | default: |
429 | return QByteArray(); |
430 | } |
431 | } |
432 | |
433 | QByteArray uniformTypeName(QSSGRenderShaderValue::Type type) |
434 | { |
435 | switch (type) { |
436 | case QSSGRenderShaderValue::Float: |
437 | return ShaderType<QMetaType::Double>::name(); |
438 | case QSSGRenderShaderValue::Boolean: |
439 | return ShaderType<QMetaType::Bool>::name(); |
440 | case QSSGRenderShaderValue::Integer: |
441 | return ShaderType<QMetaType::Int>::name(); |
442 | case QSSGRenderShaderValue::Vec2: |
443 | return ShaderType<QMetaType::QVector2D>::name(); |
444 | case QSSGRenderShaderValue::Vec3: |
445 | return ShaderType<QMetaType::QVector3D>::name(); |
446 | case QSSGRenderShaderValue::Vec4: |
447 | return ShaderType<QMetaType::QVector4D>::name(); |
448 | case QSSGRenderShaderValue::Rgba: |
449 | return ShaderType<QMetaType::QColor>::name(); |
450 | case QSSGRenderShaderValue::Size: |
451 | return ShaderType<QMetaType::QSize>::name(); |
452 | case QSSGRenderShaderValue::SizeF: |
453 | return ShaderType<QMetaType::QSizeF>::name(); |
454 | case QSSGRenderShaderValue::Point: |
455 | return ShaderType<QMetaType::QPoint>::name(); |
456 | case QSSGRenderShaderValue::PointF: |
457 | return ShaderType<QMetaType::QPointF>::name(); |
458 | case QSSGRenderShaderValue::Rect: |
459 | return ShaderType<QMetaType::QRect>::name(); |
460 | case QSSGRenderShaderValue::RectF: |
461 | return ShaderType<QMetaType::QRectF>::name(); |
462 | case QSSGRenderShaderValue::Quaternion: |
463 | return ShaderType<QMetaType::QQuaternion>::name(); |
464 | case QSSGRenderShaderValue::Matrix4x4: |
465 | return ShaderType<QMetaType::QMatrix4x4>::name(); |
466 | default: |
467 | return QByteArray(); |
468 | } |
469 | } |
470 | |
471 | QSSGRenderShaderValue::Type uniformType(QMetaType type) |
472 | { |
473 | switch (type.id()) { |
474 | case QMetaType::Double: |
475 | case QMetaType::Float: |
476 | return ShaderType<QMetaType::Double>::type(); |
477 | case QMetaType::Bool: |
478 | return ShaderType<QMetaType::Bool>::type(); |
479 | case QMetaType::QVector2D: |
480 | return ShaderType<QMetaType::QVector2D>::type(); |
481 | case QMetaType::QVector3D: |
482 | return ShaderType<QMetaType::QVector3D>::type(); |
483 | case QMetaType::QVector4D: |
484 | return ShaderType<QMetaType::QVector4D>::type(); |
485 | case QMetaType::Int: |
486 | return ShaderType<QMetaType::Int>::type(); |
487 | case QMetaType::QColor: |
488 | return ShaderType<QMetaType::QColor>::type(); |
489 | case QMetaType::QSize: |
490 | return ShaderType<QMetaType::QSize>::type(); |
491 | case QMetaType::QSizeF: |
492 | return ShaderType<QMetaType::QSizeF>::type(); |
493 | case QMetaType::QPoint: |
494 | return ShaderType<QMetaType::QPoint>::type(); |
495 | case QMetaType::QPointF: |
496 | return ShaderType<QMetaType::QPointF>::type(); |
497 | case QMetaType::QRect: |
498 | return ShaderType<QMetaType::QRect>::type(); |
499 | case QMetaType::QRectF: |
500 | return ShaderType<QMetaType::QRectF>::type(); |
501 | case QMetaType::QQuaternion: |
502 | return ShaderType<QMetaType::QQuaternion>::type(); |
503 | case QMetaType::QMatrix4x4: |
504 | return ShaderType<QMetaType::QMatrix4x4>::type(); |
505 | default: |
506 | return QSSGRenderShaderValue::Unknown; |
507 | } |
508 | } |
509 | |
510 | MetaTypeList supportedMetatypes() |
511 | { |
512 | return {std::begin(arr: qssg_metatype_list), std::end(arr: qssg_metatype_list)}; |
513 | } |
514 | |
515 | } |
516 | |
517 | QQuick3DShaderUtilsBuffer::TextureFormat QQuick3DShaderUtilsBuffer::mapRenderTextureFormat(QSSGRenderTextureFormat::Format fmt) |
518 | { |
519 | using TextureFormat = QQuick3DShaderUtilsBuffer::TextureFormat; |
520 | switch (fmt) { |
521 | case QSSGRenderTextureFormat::RGBA8: return TextureFormat::RGBA8; |
522 | case QSSGRenderTextureFormat::RGBA16F: return TextureFormat::RGBA16F; |
523 | case QSSGRenderTextureFormat::RGBA32F: return TextureFormat::RGBA32F; |
524 | case QSSGRenderTextureFormat::R8: return TextureFormat::R8; |
525 | case QSSGRenderTextureFormat::R16: return TextureFormat::R16; |
526 | case QSSGRenderTextureFormat::R16F: return TextureFormat::R16F; |
527 | case QSSGRenderTextureFormat::R32F: return TextureFormat::R32F; |
528 | default: |
529 | break; |
530 | } |
531 | return TextureFormat::Unknown; |
532 | } |
533 | |
534 | QSSGRenderTextureFormat::Format QQuick3DShaderUtilsBuffer::mapTextureFormat(QQuick3DShaderUtilsBuffer::TextureFormat fmt) |
535 | { |
536 | using TextureFormat = QQuick3DShaderUtilsBuffer::TextureFormat; |
537 | switch (fmt) { |
538 | case TextureFormat::RGBA8: return QSSGRenderTextureFormat::RGBA8; |
539 | case TextureFormat::RGBA16F: return QSSGRenderTextureFormat::RGBA16F; |
540 | case TextureFormat::RGBA32F: return QSSGRenderTextureFormat::RGBA32F; |
541 | case TextureFormat::R8: return QSSGRenderTextureFormat::R8; |
542 | case TextureFormat::R16: return QSSGRenderTextureFormat::R16; |
543 | case TextureFormat::R16F: return QSSGRenderTextureFormat::R16F; |
544 | case TextureFormat::R32F: return QSSGRenderTextureFormat::R32F; |
545 | default: |
546 | break; |
547 | } |
548 | return QSSGRenderTextureFormat::Unknown; |
549 | } |
550 | |
551 | QQuick3DShaderUtilsBuffer::TextureFormat QQuick3DShaderUtilsBuffer::format() const |
552 | { |
553 | return mapRenderTextureFormat(fmt: command.m_format.format); |
554 | } |
555 | |
556 | void QQuick3DShaderUtilsBuffer::setFormat(TextureFormat format) |
557 | { |
558 | command.m_format = mapTextureFormat(fmt: format); |
559 | } |
560 | |
561 | void QQuick3DShaderUtilsRenderPass::qmlAppendCommand(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list, |
562 | QQuick3DShaderUtilsRenderCommand *command) |
563 | { |
564 | if (!command) |
565 | return; |
566 | |
567 | QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object); |
568 | that->m_commands.push_back(t: command); |
569 | } |
570 | |
571 | QQuick3DShaderUtilsRenderCommand *QQuick3DShaderUtilsRenderPass::qmlCommandAt(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list, |
572 | qsizetype index) |
573 | { |
574 | QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object); |
575 | return that->m_commands.at(i: index); |
576 | } |
577 | |
578 | qsizetype QQuick3DShaderUtilsRenderPass::qmlCommandCount(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list) |
579 | { |
580 | QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object); |
581 | return that->m_commands.size(); |
582 | } |
583 | |
584 | void QQuick3DShaderUtilsRenderPass::qmlCommandClear(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list) |
585 | { |
586 | QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object); |
587 | that->m_commands.clear(); |
588 | } |
589 | |
590 | QQmlListProperty<QQuick3DShaderUtilsRenderCommand> QQuick3DShaderUtilsRenderPass::commands() |
591 | { |
592 | return QQmlListProperty<QQuick3DShaderUtilsRenderCommand>(this, |
593 | nullptr, |
594 | QQuick3DShaderUtilsRenderPass::qmlAppendCommand, |
595 | QQuick3DShaderUtilsRenderPass::qmlCommandCount, |
596 | QQuick3DShaderUtilsRenderPass::qmlCommandAt, |
597 | QQuick3DShaderUtilsRenderPass::qmlCommandClear); |
598 | } |
599 | |
600 | void QQuick3DShaderUtilsRenderPass::qmlAppendShader(QQmlListProperty<QQuick3DShaderUtilsShader> *list, |
601 | QQuick3DShaderUtilsShader *shader) |
602 | { |
603 | if (!shader) |
604 | return; |
605 | |
606 | QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object); |
607 | |
608 | // An append implementation CANNOT rely on the object (shader in this case) |
609 | // being complete. When the list references a Shader object living under |
610 | // another Effect, its properties may not be set at the point of this |
611 | // function being called, so accessing shader->stage is not allowed since |
612 | // it may still have its default value, not what is set from QML... |
613 | |
614 | // the only thing we can do is to append to our list, do not try to be clever |
615 | that->m_shaders.append(t: shader); |
616 | |
617 | connect(sender: shader, signal: &QQuick3DShaderUtilsShader::shaderChanged, context: that, slot: &QQuick3DShaderUtilsRenderPass::changed); |
618 | connect(sender: shader, signal: &QQuick3DShaderUtilsShader::stageChanged, context: that, slot: &QQuick3DShaderUtilsRenderPass::changed); |
619 | |
620 | emit that->changed(); |
621 | } |
622 | |
623 | QQuick3DShaderUtilsShader *QQuick3DShaderUtilsRenderPass::qmlShaderAt(QQmlListProperty<QQuick3DShaderUtilsShader> *list, |
624 | qsizetype index) |
625 | { |
626 | QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object); |
627 | return that->m_shaders.at(idx: index); |
628 | } |
629 | |
630 | qsizetype QQuick3DShaderUtilsRenderPass::qmlShaderCount(QQmlListProperty<QQuick3DShaderUtilsShader> *list) |
631 | { |
632 | QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object); |
633 | return that->m_shaders.size(); |
634 | } |
635 | |
636 | void QQuick3DShaderUtilsRenderPass::qmlShaderClear(QQmlListProperty<QQuick3DShaderUtilsShader> *list) |
637 | { |
638 | QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object); |
639 | |
640 | for (QQuick3DShaderUtilsShader *shader : that->m_shaders) |
641 | shader->disconnect(receiver: that); |
642 | |
643 | that->m_shaders.clear(); |
644 | |
645 | emit that->changed(); |
646 | } |
647 | |
648 | QQmlListProperty<QQuick3DShaderUtilsShader> QQuick3DShaderUtilsRenderPass::shaders() |
649 | { |
650 | return QQmlListProperty<QQuick3DShaderUtilsShader>(this, |
651 | nullptr, |
652 | QQuick3DShaderUtilsRenderPass::qmlAppendShader, |
653 | QQuick3DShaderUtilsRenderPass::qmlShaderCount, |
654 | QQuick3DShaderUtilsRenderPass::qmlShaderAt, |
655 | QQuick3DShaderUtilsRenderPass::qmlShaderClear); |
656 | } |
657 | |
658 | QQuick3DShaderUtilsTextureInput::QQuick3DShaderUtilsTextureInput(QObject *p) : QObject(p) {} |
659 | |
660 | QQuick3DShaderUtilsTextureInput::~QQuick3DShaderUtilsTextureInput() |
661 | { |
662 | } |
663 | |
664 | void QQuick3DShaderUtilsTextureInput::setTexture(QQuick3DTexture *texture) |
665 | { |
666 | if (m_texture == texture) |
667 | return; |
668 | |
669 | QObject *p = parent(); |
670 | while (p != nullptr) { |
671 | if (QQuick3DCustomMaterial *mat = qobject_cast<QQuick3DCustomMaterial *>(object: p)) { |
672 | mat->setDynamicTextureMap(this); |
673 | QQuick3DObjectPrivate::attachWatcherPriv(sceneContext: mat, callContext: this, setter: &QQuick3DShaderUtilsTextureInput::setTexture, newO: texture, oldO: m_texture); |
674 | break; |
675 | } else if (QQuick3DEffect *efx = qobject_cast<QQuick3DEffect *>(object: p)) { |
676 | efx->setDynamicTextureMap(this); |
677 | QQuick3DObjectPrivate::attachWatcherPriv(sceneContext: efx, callContext: this, setter: &QQuick3DShaderUtilsTextureInput::setTexture, newO: texture, oldO: m_texture); |
678 | break; |
679 | } |
680 | p = p->parent(); |
681 | } |
682 | |
683 | if (p == nullptr) { |
684 | qWarning(msg: "A texture was defined out of Material or Effect" ); |
685 | } |
686 | |
687 | m_texture = texture; |
688 | Q_EMIT textureChanged(); |
689 | } |
690 | |
691 | QT_END_NAMESPACE |
692 | |