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
14QT_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
236namespace QSSGShaderUtils {
237
238ResolveFunction resolveShaderOverride = nullptr;
239
240void setResolveFunction(ResolveFunction fn)
241{
242 resolveShaderOverride = fn;
243}
244
245QByteArray 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.
271static 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
289template<>
290struct ShaderType<QMetaType::Double>
291{
292 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Float; }
293 static QByteArray name() { return QByteArrayLiteral("float"); }
294};
295
296template<>
297struct ShaderType<QMetaType::Bool>
298{
299 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Boolean; }
300 static QByteArray name() { return QByteArrayLiteral("bool"); }
301};
302
303template<>
304struct ShaderType<QMetaType::Int>
305{
306 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Integer; }
307 static QByteArray name() { return QByteArrayLiteral("int"); }
308};
309
310template<>
311struct ShaderType<QMetaType::QVector2D>
312{
313 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Vec2; }
314 static QByteArray name() { return QByteArrayLiteral("vec2"); }
315};
316
317template<>
318struct ShaderType<QMetaType::QVector3D>
319{
320 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Vec3; }
321 static QByteArray name() { return QByteArrayLiteral("vec3"); }
322};
323
324template<>
325struct ShaderType<QMetaType::QVector4D>
326{
327 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Vec4; }
328 static QByteArray name() { return QByteArrayLiteral("vec4"); }
329};
330
331template<>
332struct ShaderType<QMetaType::QColor>
333{
334 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Rgba; }
335 static QByteArray name() { return QByteArrayLiteral("vec4"); }
336};
337
338template<>
339struct ShaderType<QMetaType::QSize>
340{
341 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Size; }
342 static QByteArray name() { return QByteArrayLiteral("vec2"); }
343};
344
345template<>
346struct ShaderType<QMetaType::QSizeF>
347{
348 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::SizeF; }
349 static QByteArray name() { return QByteArrayLiteral("vec2"); }
350};
351
352template<>
353struct ShaderType<QMetaType::QPoint>
354{
355 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Point; }
356 static QByteArray name() { return QByteArrayLiteral("vec2"); }
357};
358
359template<>
360struct ShaderType<QMetaType::QPointF>
361{
362 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::PointF; }
363 static QByteArray name() { return QByteArrayLiteral("vec2"); }
364};
365
366template<>
367struct ShaderType<QMetaType::QRect>
368{
369 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Rect; }
370 static QByteArray name() { return QByteArrayLiteral("vec4"); }
371};
372
373template<>
374struct ShaderType<QMetaType::QRectF>
375{
376 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::RectF; }
377 static QByteArray name() { return QByteArrayLiteral("vec4"); }
378};
379
380template<>
381struct ShaderType<QMetaType::QQuaternion>
382{
383 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Quaternion; }
384 static QByteArray name() { return QByteArrayLiteral("vec4"); }
385};
386
387template<>
388struct ShaderType<QMetaType::QMatrix4x4>
389{
390 static constexpr QSSGRenderShaderValue::Type type() { return QSSGRenderShaderValue::Matrix4x4; }
391 static QByteArray name() { return QByteArrayLiteral("mat4"); }
392};
393
394QByteArray 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
433QByteArray 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
471QSSGRenderShaderValue::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
510MetaTypeList supportedMetatypes()
511{
512 return {std::begin(arr: qssg_metatype_list), std::end(arr: qssg_metatype_list)};
513}
514
515}
516
517QQuick3DShaderUtilsBuffer::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
534QSSGRenderTextureFormat::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
551QQuick3DShaderUtilsBuffer::TextureFormat QQuick3DShaderUtilsBuffer::format() const
552{
553 return mapRenderTextureFormat(fmt: command.m_format.format);
554}
555
556void QQuick3DShaderUtilsBuffer::setFormat(TextureFormat format)
557{
558 command.m_format = mapTextureFormat(fmt: format);
559}
560
561void 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
571QQuick3DShaderUtilsRenderCommand *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
578qsizetype QQuick3DShaderUtilsRenderPass::qmlCommandCount(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list)
579{
580 QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object);
581 return that->m_commands.size();
582}
583
584void QQuick3DShaderUtilsRenderPass::qmlCommandClear(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list)
585{
586 QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object);
587 that->m_commands.clear();
588}
589
590QQmlListProperty<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
600void 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
623QQuick3DShaderUtilsShader *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
630qsizetype QQuick3DShaderUtilsRenderPass::qmlShaderCount(QQmlListProperty<QQuick3DShaderUtilsShader> *list)
631{
632 QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(object: list->object);
633 return that->m_shaders.size();
634}
635
636void 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
648QQmlListProperty<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
658QQuick3DShaderUtilsTextureInput::QQuick3DShaderUtilsTextureInput(QObject *p) : QObject(p) {}
659
660QQuick3DShaderUtilsTextureInput::~QQuick3DShaderUtilsTextureInput()
661{
662}
663
664void 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
691QT_END_NAMESPACE
692

source code of qtquick3d/src/quick3d/qquick3dshaderutils.cpp