1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Quick 3D.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include "qquick3dshaderutils_p.h"
31 
32 #include <QtCore/qfile.h>
33 #include <QtQml/qqml.h>
34 #include <QtQml/qqmlcontext.h>
35 
36 #include <QtQuick3D/private/qquick3dmaterial_p.h>
37 #include <QtQuick3D/private/qquick3deffect_p.h>
38 
39 QT_BEGIN_NAMESPACE
40 
41 /*!
42     \qmltype Shader
43     \inherits Object
44     \inqmlmodule QtQuick3D
45     \brief Container component for defining shader code used by CustomMaterials and Effects.
46 */
47 /*!
48     \qmlproperty string Shader::shader
49     Specifies the name of the shader source file.
50 */
51 /*!
52     \qmlproperty enumeration Shader::stage
53     Specifies the shader stage. The default is \c Shader.Shared
54 
55     \value Shader.Shared The shader can be shared among different stages
56     \value Shader.Vertex The shader is a vertex shader
57     \value Shader.Fragment The shader is a fragment shader
58     \value Shader.Geometry The shader is a geometry shader
59     \value Shader.Compute The shader is a compute shader
60 */
61 
62 /*!
63     \qmltype ShaderInfo
64     \inherits Object
65     \inqmlmodule QtQuick3D
66     \brief Defines basic information about custom shader code for CustomMaterials.
67 */
68 /*!
69     \qmlproperty string ShaderInfo::version
70     Specifies the shader code version.
71 */
72 /*!
73     \qmlproperty string ShaderInfo::type
74     Specifies the shader code type.
75 */
76 /*!
77     \qmlproperty string ShaderInfo::shaderKey
78     Specifies the options used by the shader using the combination of shader key values.
79 
80     \value ShaderInfo.Diffuse The shader uses diffuse lighting.
81     \value ShaderInfo.Specular The shader uses specular lighting.
82     \value ShaderInfo.Cutout The shader uses alpha cutout.
83     \value ShaderInfo.Refraction The shader uses refraction.
84     \value ShaderInfo.Transparent The shader uses transparency.
85     \value ShaderInfo.Displace The shader uses displacement mapping.
86     \value ShaderInfo.Transmissive The shader uses transmissiveness.
87     \value ShaderInfo.Glossy The shader is default glossy. This is a combination of \c ShaderInfo.Diffuse and
88         \c ShaderInfo.Specular.
89 */
90 
91 /*!
92     \qmltype TextureInput
93     \inherits Object
94     \inqmlmodule QtQuick3D
95     \brief Defines a texture channel for a Custom Material or an Effect.
96 */
97 /*!
98     \qmlproperty Texture TextureInput::texture
99     Specifies the Texture to input.
100 */
101 /*!
102     \qmlproperty bool TextureInput::enabled
103     The property determines if this TextureInput is enabled.
104 */
105 
106 /*!
107     \qmltype Pass
108     \inherits Object
109     \inqmlmodule QtQuick3D
110     \brief Defines a render pass in the CustomMaterial or the Effect.
111 */
112 /*!
113     \qmlproperty Buffer Pass::output
114     Specifies the output \l {Buffer}{buffer} of the pass.
115 */
116 /*!
117     \qmlproperty list Pass::commands
118     Specifies the list of render \l {Command}{commands} of the pass.
119 */
120 /*!
121     \qmlproperty list Pass::shaders
122     Specifies the list of \l {Shader}{shaders} of the pass.
123 */
124 
125 /*!
126     \qmltype Command
127     \inherits Object
128     \inqmlmodule QtQuick3D
129     \brief Defines a command to be performed in a pass of a CustomMaterial or an Effect.
130 */
131 
132 /*!
133     \qmltype BufferInput
134     \inherits Command
135     \inqmlmodule QtQuick3D
136     \brief Defines an input buffer to be used for a pass of a CustomMaterial or an Effect.
137 */
138 /*!
139     \qmlproperty Buffer BufferInput::buffer
140     Specifies the \l {Buffer}{buffer} used for the parameter.
141 */
142 /*!
143     \qmlproperty string BufferInput::param
144     Specifies the name of the input parameter in the shader.
145 */
146 
147 /*!
148     \qmltype BufferBlit
149     \inherits Command
150     \inqmlmodule QtQuick3D
151     \brief Defines a copy operation between two buffers in a pass of a CustomMaterial or an Effect.
152 */
153 /*!
154     \qmlproperty Buffer BufferBlit::source
155     Specifies the source \l {Buffer}{buffer} of the copy operation.
156 */
157 /*!
158     \qmlproperty Buffer BufferBlit::destination
159     Specifies the destination \l {Buffer}{buffer} of the copy operation.
160 */
161 
162 /*!
163     \qmltype Blending
164     \inherits Command
165     \inqmlmodule QtQuick3D
166     \brief Defines the blending state in a pass of a CustomMaterial or an Effect.
167 */
168 /*!
169     \qmlproperty enumeration Blending::srcBlending
170     Specifies the source blending function.
171 
172     \value Blending.Unknown
173     \value Blending.Zero
174     \value Blending.One
175     \value Blending.SrcColor
176     \value Blending.OneMinusSrcColor
177     \value Blending.DstColor
178     \value Blending.OneMinusDstColor
179     \value Blending.SrcAlpha
180     \value Blending.OneMinusSrcAlpha
181     \value Blending.DstAlpha
182     \value Blending.OneMinusDstAlpha
183     \value Blending.ConstantColor
184     \value Blending.OneMinusConstantColor
185     \value Blending.ConstantAlpha
186     \value Blending.OneMinusConstantAlpha
187     \value Blending.SrcAlphaSaturate
188 
189 */
190 /*!
191     \qmlproperty enumeration Blending::destBlending
192     Specifies the destination blending function.
193 
194     \value Blending.Unknown
195     \value Blending.Zero
196     \value Blending.One
197     \value Blending.SrcColor
198     \value Blending.OneMinusSrcColor
199     \value Blending.DstColor
200     \value Blending.OneMinusDstColor
201     \value Blending.SrcAlpha
202     \value Blending.OneMinusSrcAlpha
203     \value Blending.DstAlpha
204     \value Blending.OneMinusDstAlpha
205     \value Blending.ConstantColor
206     \value Blending.OneMinusConstantColor
207     \value Blending.ConstantAlpha
208     \value Blending.OneMinusConstantAlpha
209 */
210 
211 /*!
212     \qmltype Buffer
213     \inherits Object
214     \inqmlmodule QtQuick3D
215     \brief Defines a buffer to be used for a pass of a CustomMaterial or an Effect.
216 */
217 /*!
218     \qmlproperty enumeration Buffer::format
219     Specifies the buffer format.
220 
221     \value Buffer.Unknown
222     \value Buffer.R8
223     \value Buffer.R16
224     \value Buffer.R16F
225     \value Buffer.R32I
226     \value Buffer.R32UI
227     \value Buffer.R32F
228     \value Buffer.RG8
229     \value Buffer.RGBA8
230     \value Buffer.RGB8
231     \value Buffer.SRGB8
232     \value Buffer.SRGB8A8
233     \value Buffer.RGB565
234     \value Buffer.RGBA16F
235     \value Buffer.RG16F
236     \value Buffer.RG32F
237     \value Buffer.RGB32F
238     \value Buffer.RGBA32F
239     \value Buffer.R11G11B10
240     \value Buffer.RGB9E5
241     \value Buffer.Depth16
242     \value Buffer.Depth24
243     \value Buffer.Depth32
244     \value Buffer.Depth24Stencil8
245 */
246 /*!
247     \qmlproperty enumeration Buffer::textureFilterOperation
248     Specifies the filter operation when a render \l {Pass}{pass} is reading the buffer that is
249     different size as the current output buffer.
250 
251     \value Buffer.Unknown Value not set.
252     \value Buffer.Nearest Use nearest-neighbor.
253     \value Buffer.Linear Use linear filtering.
254 */
255 /*!
256     \qmlproperty enumeration Buffer::textureCoordOperation
257     Specifies the texture coordinate operation for coordinates outside [0, 1] range.
258 
259     \value Buffer.Unknown Value not set.
260     \value Buffer.ClampToEdge Clamp coordinate to edge.
261     \value Buffer.MirroredRepeat Repeat the coordinate, but flip direction at the beginning and end.
262     \value Buffer.Repeat Repeat the coordinate always from the beginning.
263 */
264 /*!
265     \qmlproperty real Buffer::sizeMultiplier
266     Specifies the size multiplier of the buffer. \c 1.0 creates buffer with the same size while
267     \c 0.5 creates buffer with width and height halved.
268 */
269 /*!
270     \qmlproperty enumeration Buffer::bufferFlags
271     Specifies the buffer allocation flags.
272 
273     \value Buffer.None Value not set.
274     \value Buffer.SceneLifetime The buffer is allocated for the whole lifetime of the scene.
275 */
276 /*!
277     \qmlproperty string Buffer::name
278     Specifies the name of the buffer
279 */
280 
281 /*!
282     \qmltype RenderState
283     \inherits Command
284     \inqmlmodule QtQuick3D
285     \brief Defines the render state to be disabled in a pass of a CustomMaterial or an Effect.
286 */
287 /*!
288     \qmlproperty enumeration RenderState::renderState
289     Specifies the render state to enable/disable in a \l {Pass}{pass}.
290 
291     \value RenderState.Unknown
292     \value RenderState.Blend
293     \value RenderState.CullFace
294     \value RenderState.DepthTest
295     \value RenderState.StencilTest
296     \value RenderState.ScissorTest
297     \value RenderState.DepthWrite
298     \value RenderState.Multisample
299 */
300 /*!
301     \qmlproperty bool RenderState::enable
302     Specifies if the state is enabled or disabled.
303 */
304 
305 /*!
306     \qmltype CullMode
307     \inherits Command
308     \inqmlmodule QtQuick3D
309     \brief Defines the cull mode for render pass.
310     \since 5.15
311 
312     \note This command can only be used with the CustomMaterial.
313 */
314 /*!
315     \qmlproperty enumeration CullMode::cullMode
316     Specifies the culling mode in a \l {Pass}{pass} when \c RenderState.CullFace is enabled.
317     The material culling mode is overridden.
318 
319     \value Material.BackFaceCulling
320     \value Material.FrontFaceCulling
321     \value Material.NoCulling
322 */
323 
324 /*!
325     \qmltype DepthInput
326     \inherits Command
327     \inqmlmodule QtQuick3D
328     \brief Defines the output texture for the depth buffer.
329     \since 5.15
330 */
331 /*!
332     \qmlproperty string DepthInput::param
333     Specifies the name of the texture the depth buffer will bind to.
334 */
335 
336 /*!
337     \qmltype SetUniformValue
338     \inherits Command
339     \inqmlmodule QtQuick3D
340     \brief Defines a value to be set during a single \l {Pass}{pass}.
341     \since 5.15
342 
343     \note The value set by this command is will only be set during the \l {Pass}{pass} it occurs in.
344     For consecutive passes the value will be revert to the initial value of the uniform as it
345     was defined in the effect or custom material item.
346 */
347 /*!
348     \qmlproperty string SetUniformValue::target
349     Specifies the name of the uniform that will have its value changed during the \l {Pass}{pass}.
350 */
351 /*!
352     \qmlproperty Variant SetUniformValue::value
353     Specifies the value that will be set on the \c target uniform.
354 */
355 
addSnapperSampler(const QByteArray & texName,QByteArray & shaderPrefix)356 void QSSGShaderUtils::addSnapperSampler(const QByteArray &texName, QByteArray &shaderPrefix)
357 {
358     const char *filter = "linear";
359     const char *clamp = "clamp";
360     // Output macro so we can change the set of variables used for this
361     // independent of the
362     // meta data system.
363     shaderPrefix.append("SNAPPER_SAMPLER2D(");
364     shaderPrefix.append(texName);
365     shaderPrefix.append(", ");
366     shaderPrefix.append(texName);
367     shaderPrefix.append(", ");
368     shaderPrefix.append(filter);
369     shaderPrefix.append(", ");
370     shaderPrefix.append(clamp);
371     shaderPrefix.append(", ");
372     shaderPrefix.append("false )\n");
373 }
374 
resolveShader(const QByteArray & shader,QByteArray & shaderPath,const QObject * qmlObj)375 QByteArray QSSGShaderUtils::resolveShader(const QByteArray &shader, QByteArray &shaderPath,
376                                           const QObject *qmlObj)
377 {
378     if (!shaderPath.isEmpty())
379         shaderPath.append('>');
380 
381     int offset = -1;
382     if (shader.startsWith("qrc:/"))
383         offset = 3;
384     else if (shader.startsWith("file:/"))
385         offset = 6;
386     else if (shader.startsWith(":/"))
387         offset = 0;
388 
389     QString path;
390     if (offset == -1) {
391         QUrl u(QString::fromUtf8(shader));
392         if (u.isLocalFile())
393             path = u.toLocalFile();
394     }
395 
396     if (offset == -1 && path.isEmpty())
397         path = QString::fromLatin1(":/") + QString::fromLocal8Bit(shader);
398     else
399         path = QString::fromLocal8Bit(shader.constData() + offset);
400 
401     QFile f(path);
402     if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
403         shaderPath += path.toLatin1();
404         return f.readAll();
405     } else if (offset == -1) {
406         // Plain schemeless string can also be a local file instead of resource, so let's try to
407         // load a local file relative to qml context
408         QQmlContext *context = qmlContext(qmlObj);
409         if (context) {
410             QUrl resolvedUrl = context->resolvedUrl(QUrl(QString::fromUtf8(shader)));
411             path = resolvedUrl.toLocalFile();
412             QFile file(path);
413             if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
414                 shaderPath += path.toLatin1();
415                 return file.readAll();
416             }
417         }
418     }
419 
420     shaderPath += QByteArrayLiteral("Inline_") + QByteArray::number(qHash(shader, uint(qGlobalQHashSeed())));
421 
422     return shader;
423 }
424 
mergeShaderCode(const QByteArray & shared,const QByteArray & uniforms,const QByteArray & textures,const QByteArray & vertex,const QByteArray & geometry,const QByteArray & fragment)425 QByteArray QSSGShaderUtils::mergeShaderCode(const QByteArray &shared,
426                                             const QByteArray &uniforms,
427                                             const QByteArray &textures,
428                                             const QByteArray &vertex,
429                                             const QByteArray &geometry,
430                                             const QByteArray &fragment)
431 {
432     QByteArray shaderCode;
433     // Shared
434     if (!shared.isEmpty())
435         shaderCode.append(shared);
436 
437     if (!textures.isEmpty())
438         shaderCode.append(textures);
439 
440     if (!uniforms.isEmpty())
441         shaderCode.append(uniforms);
442 
443     // Vetex
444     shaderCode.append(QByteArrayLiteral("\n#ifdef VERTEX_SHADER\n"));
445     if (!vertex.isEmpty())
446         shaderCode.append(vertex);
447     else
448         shaderCode.append(QByteArrayLiteral("void vert(){}"));
449     shaderCode.append(QByteArrayLiteral("\n#endif\n"));
450 
451     // Geometry
452     if (!geometry.isEmpty()) {
453         shaderCode.append(QByteArrayLiteral("\n#ifdef USER_GEOMETRY_SHADER\n"));
454         shaderCode.append(geometry);
455         shaderCode.append(QByteArrayLiteral("\n#endif\n"));
456     }
457 
458     // Fragment
459     shaderCode.append(QByteArrayLiteral("\n#ifdef FRAGMENT_SHADER\n"));
460     if (!fragment.isEmpty())
461         shaderCode.append(fragment);
462     else
463         shaderCode.append(QByteArrayLiteral("void frag(){}"));
464     shaderCode.append(QByteArrayLiteral("\n#endif\n"));
465 
466     return shaderCode;
467 }
468 
mapRenderTextureFormat(QSSGRenderTextureFormat::Format fmt)469 QQuick3DShaderUtilsBuffer::TextureFormat QQuick3DShaderUtilsBuffer::mapRenderTextureFormat(QSSGRenderTextureFormat::Format fmt)
470 {
471     using TextureFormat = QQuick3DShaderUtilsBuffer::TextureFormat;
472     switch (fmt) {
473     case QSSGRenderTextureFormat::R8: return TextureFormat::R8;
474     case QSSGRenderTextureFormat::R16: return TextureFormat::R16;
475     case QSSGRenderTextureFormat::R16F: return TextureFormat::R16F;
476     case QSSGRenderTextureFormat::R32I: return TextureFormat::R32I;
477     case QSSGRenderTextureFormat::R32UI: return TextureFormat::R32UI;
478     case QSSGRenderTextureFormat::R32F: return TextureFormat::R32F;
479     case QSSGRenderTextureFormat::RG8: return TextureFormat::RG8;
480     case QSSGRenderTextureFormat::RGBA8: return TextureFormat::RGBA8;
481     case QSSGRenderTextureFormat::RGB8: return TextureFormat::RGB8;
482     case QSSGRenderTextureFormat::SRGB8: return TextureFormat::SRGB8;
483     case QSSGRenderTextureFormat::SRGB8A8: return TextureFormat::SRGB8A8;
484     case QSSGRenderTextureFormat::RGB565: return TextureFormat::RGB565;
485     case QSSGRenderTextureFormat::RGBA16F: return TextureFormat::RGBA16F;
486     case QSSGRenderTextureFormat::RG16F: return TextureFormat::RG16F;
487     case QSSGRenderTextureFormat::RG32F: return TextureFormat::RG32F;
488     case QSSGRenderTextureFormat::RGB32F: return TextureFormat::RGB32F;
489     case QSSGRenderTextureFormat::RGBA32F: return TextureFormat::RGBA32F;
490     case QSSGRenderTextureFormat::R11G11B10: return TextureFormat::R11G11B10;
491     case QSSGRenderTextureFormat::RGB9E5: return TextureFormat::RGB9E5;
492     case QSSGRenderTextureFormat::Depth16: return TextureFormat::Depth16;
493     case QSSGRenderTextureFormat::Depth24: return TextureFormat::Depth24;
494     case QSSGRenderTextureFormat::Depth32: return TextureFormat::Depth32;
495     case QSSGRenderTextureFormat::Depth24Stencil8: return TextureFormat::Depth24Stencil8;
496     default:
497         break;
498     }
499     return TextureFormat::Unknown;
500 }
501 
mapTextureFormat(QQuick3DShaderUtilsBuffer::TextureFormat fmt)502 QSSGRenderTextureFormat::Format QQuick3DShaderUtilsBuffer::mapTextureFormat(QQuick3DShaderUtilsBuffer::TextureFormat fmt)
503 {
504     using TextureFormat = QQuick3DShaderUtilsBuffer::TextureFormat;
505     switch (fmt) {
506     case TextureFormat::R8: return QSSGRenderTextureFormat::R8;
507     case TextureFormat::R16: return QSSGRenderTextureFormat::R16;
508     case TextureFormat::R16F: return QSSGRenderTextureFormat::R16F;
509     case TextureFormat::R32I: return QSSGRenderTextureFormat::R32I;
510     case TextureFormat::R32UI: return QSSGRenderTextureFormat::R32UI;
511     case TextureFormat::R32F: return QSSGRenderTextureFormat::R32F;
512     case TextureFormat::RG8: return QSSGRenderTextureFormat::RG8;
513     case TextureFormat::RGBA8: return QSSGRenderTextureFormat::RGBA8;
514     case TextureFormat::RGB8: return QSSGRenderTextureFormat::RGB8;
515     case TextureFormat::SRGB8: return QSSGRenderTextureFormat::SRGB8;
516     case TextureFormat::SRGB8A8: return QSSGRenderTextureFormat::SRGB8A8;
517     case TextureFormat::RGB565: return QSSGRenderTextureFormat::RGB565;
518     case TextureFormat::RGBA16F: return QSSGRenderTextureFormat::RGBA16F;
519     case TextureFormat::RG16F: return QSSGRenderTextureFormat::RG16F;
520     case TextureFormat::RG32F: return QSSGRenderTextureFormat::RG32F;
521     case TextureFormat::RGB32F: return QSSGRenderTextureFormat::RGB32F;
522     case TextureFormat::RGBA32F: return QSSGRenderTextureFormat::RGBA32F;
523     case TextureFormat::R11G11B10: return QSSGRenderTextureFormat::R11G11B10;
524     case TextureFormat::RGB9E5: return QSSGRenderTextureFormat::RGB9E5;
525     case TextureFormat::Depth16: return QSSGRenderTextureFormat::Depth16;
526     case TextureFormat::Depth24: return QSSGRenderTextureFormat::Depth24;
527     case TextureFormat::Depth32: return QSSGRenderTextureFormat::Depth32;
528     case TextureFormat::Depth24Stencil8: return QSSGRenderTextureFormat::Depth24Stencil8;
529     default:
530         break;
531     }
532     return QSSGRenderTextureFormat::Unknown;
533 }
534 
format() const535 QQuick3DShaderUtilsBuffer::TextureFormat QQuick3DShaderUtilsBuffer::format() const
536 {
537     return mapRenderTextureFormat(command.m_format.format);
538 }
539 
setFormat(TextureFormat format)540 void QQuick3DShaderUtilsBuffer::setFormat(TextureFormat format)
541 {
542     command.m_format = mapTextureFormat(format);
543 }
544 
qmlAppendCommand(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> * list,QQuick3DShaderUtilsRenderCommand * command)545 void QQuick3DShaderUtilsRenderPass::qmlAppendCommand(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list,
546                                                      QQuick3DShaderUtilsRenderCommand *command)
547 {
548     if (!command)
549         return;
550 
551     QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(list->object);
552     that->m_commands.push_back(command);
553 }
554 
qmlCommandAt(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> * list,int index)555 QQuick3DShaderUtilsRenderCommand *QQuick3DShaderUtilsRenderPass::qmlCommandAt(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list,
556                                                                               int index)
557 {
558     QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(list->object);
559     return that->m_commands.at(index);
560 }
561 
qmlCommandCount(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> * list)562 int QQuick3DShaderUtilsRenderPass::qmlCommandCount(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list)
563 {
564     QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(list->object);
565     return that->m_commands.count();
566 }
567 
qmlCommandClear(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> * list)568 void QQuick3DShaderUtilsRenderPass::qmlCommandClear(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list)
569 {
570     QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(list->object);
571     that->m_commands.clear();
572 }
573 
commands()574 QQmlListProperty<QQuick3DShaderUtilsRenderCommand> QQuick3DShaderUtilsRenderPass::commands()
575 {
576     return QQmlListProperty<QQuick3DShaderUtilsRenderCommand>(this,
577                                                              nullptr,
578                                                              QQuick3DShaderUtilsRenderPass::qmlAppendCommand,
579                                                              QQuick3DShaderUtilsRenderPass::qmlCommandCount,
580                                                              QQuick3DShaderUtilsRenderPass::qmlCommandAt,
581                                                              QQuick3DShaderUtilsRenderPass::qmlCommandClear);
582 }
583 
qmlAppendShader(QQmlListProperty<QQuick3DShaderUtilsShader> * list,QQuick3DShaderUtilsShader * shader)584 void QQuick3DShaderUtilsRenderPass::qmlAppendShader(QQmlListProperty<QQuick3DShaderUtilsShader> *list,
585                                                     QQuick3DShaderUtilsShader *shader)
586 {
587     if (!shader)
588         return;
589 
590     QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(list->object);
591     that->m_shaders[int(shader->stage)] = shader;
592 }
593 
qmlShaderAt(QQmlListProperty<QQuick3DShaderUtilsShader> * list,int index)594 QQuick3DShaderUtilsShader *QQuick3DShaderUtilsRenderPass::qmlShaderAt(QQmlListProperty<QQuick3DShaderUtilsShader> *list,
595                                                                       int index)
596 {
597     QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(list->object);
598     return that->m_shaders.at(index);
599 }
600 
qmlShaderCount(QQmlListProperty<QQuick3DShaderUtilsShader> * list)601 int QQuick3DShaderUtilsRenderPass::qmlShaderCount(QQmlListProperty<QQuick3DShaderUtilsShader> *list)
602 {
603     QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(list->object);
604     return that->m_shaders.count();
605 }
606 
qmlShaderClear(QQmlListProperty<QQuick3DShaderUtilsShader> * list)607 void QQuick3DShaderUtilsRenderPass::qmlShaderClear(QQmlListProperty<QQuick3DShaderUtilsShader> *list)
608 {
609     QQuick3DShaderUtilsRenderPass *that = qobject_cast<QQuick3DShaderUtilsRenderPass *>(list->object);
610     auto it = that->m_shaders.begin();
611     const auto end = that->m_shaders.end();
612     for (;it != end; ++it)
613         *it = nullptr;
614 }
615 
shaders()616 QQmlListProperty<QQuick3DShaderUtilsShader> QQuick3DShaderUtilsRenderPass::shaders()
617 {
618     return QQmlListProperty<QQuick3DShaderUtilsShader>(this,
619                                                       nullptr,
620                                                       QQuick3DShaderUtilsRenderPass::qmlAppendShader,
621                                                       QQuick3DShaderUtilsRenderPass::qmlShaderCount,
622                                                       QQuick3DShaderUtilsRenderPass::qmlShaderAt,
623                                                       QQuick3DShaderUtilsRenderPass::qmlShaderClear);
624 }
625 
setTexture(QQuick3DTexture * texture)626 void QQuick3DShaderUtilsTextureInput::setTexture(QQuick3DTexture *texture)
627 {
628     if (m_texture == texture)
629         return;
630 
631     QObject *p = parent();
632     while (p != nullptr) {
633         if (QQuick3DMaterial *mat = qobject_cast<QQuick3DMaterial *>(p)) {
634             mat->setDynamicTextureMap(texture, name);
635             break;
636         } else if (QQuick3DEffect *efx = qobject_cast<QQuick3DEffect *>(p)) {
637             efx->setDynamicTextureMap(texture, name);
638             break;
639         }
640         p = p->parent();
641     }
642 
643     if (p == nullptr) {
644         qWarning("A texture was defined out of Material or Effect");
645     }
646 
647     m_texture = texture;
648     Q_EMIT textureDirty(this);
649 }
650 
651 QT_END_NAMESPACE
652