1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5/* clang-format off */
6
7#include <QtQuick3DRuntimeRender/private/qssgshadermaterialadapter_p.h>
8#include "qssgrendercontextcore.h"
9#include <QtQuick3DRuntimeRender/private/qssgrhicustommaterialsystem_p.h>
10
11QT_BEGIN_NAMESPACE
12
13QSSGShaderMaterialAdapter::~QSSGShaderMaterialAdapter() = default;
14
15QSSGShaderMaterialAdapter *QSSGShaderMaterialAdapter::create(const QSSGRenderGraphObject &materialNode)
16{
17 switch (materialNode.type) {
18 case QSSGRenderGraphObject::Type::DefaultMaterial:
19 case QSSGRenderGraphObject::Type::PrincipledMaterial:
20 case QSSGRenderGraphObject::Type::SpecularGlossyMaterial:
21 return new QSSGShaderDefaultMaterialAdapter(static_cast<const QSSGRenderDefaultMaterial &>(materialNode));
22
23 case QSSGRenderGraphObject::Type::CustomMaterial:
24 return new QSSGShaderCustomMaterialAdapter(static_cast<const QSSGRenderCustomMaterial &>(materialNode));
25
26 default:
27 break;
28 }
29
30 return nullptr;
31}
32
33bool QSSGShaderMaterialAdapter::isUnshaded()
34{
35 return false;
36}
37
38bool QSSGShaderMaterialAdapter::hasCustomShaderSnippet(QSSGShaderCache::ShaderType)
39{
40 return false;
41}
42
43QByteArray QSSGShaderMaterialAdapter::customShaderSnippet(QSSGShaderCache::ShaderType,
44 QSSGShaderLibraryManager &,
45 bool)
46{
47 return QByteArray();
48}
49
50bool QSSGShaderMaterialAdapter::hasCustomShaderFunction(QSSGShaderCache::ShaderType,
51 const QByteArray &,
52 QSSGShaderLibraryManager &)
53{
54 return false;
55}
56
57void QSSGShaderMaterialAdapter::setCustomPropertyUniforms(char *,
58 QSSGRhiShaderPipeline &,
59 const QSSGRenderContextInterface &)
60{
61}
62
63bool QSSGShaderMaterialAdapter::usesSharedVariables()
64{
65 return false;
66}
67
68
69
70QSSGShaderDefaultMaterialAdapter::QSSGShaderDefaultMaterialAdapter(const QSSGRenderDefaultMaterial &material)
71 : m_material(material)
72{
73}
74
75bool QSSGShaderDefaultMaterialAdapter::isPrincipled()
76{
77 return m_material.type == QSSGRenderGraphObject::Type::PrincipledMaterial;
78}
79
80bool QSSGShaderDefaultMaterialAdapter::isSpecularGlossy()
81{
82 return m_material.type == QSSGRenderGraphObject::Type::SpecularGlossyMaterial;
83}
84
85bool QSSGShaderDefaultMaterialAdapter::isMetalnessEnabled()
86{
87 return m_material.isMetalnessEnabled();
88}
89
90bool QSSGShaderDefaultMaterialAdapter::isSpecularEnabled()
91{
92 return m_material.isSpecularEnabled();
93}
94
95bool QSSGShaderDefaultMaterialAdapter::isVertexColorsEnabled()
96{
97 return m_material.isVertexColorsEnabled();
98}
99
100bool QSSGShaderDefaultMaterialAdapter::isVertexColorsMaskEnabled()
101{
102 return m_material.isVertexColorsMaskEnabled();
103}
104
105bool QSSGShaderDefaultMaterialAdapter::isInvertOpacityMapValue()
106{
107 return m_material.isInvertOpacityMapValue();
108}
109
110bool QSSGShaderDefaultMaterialAdapter::isBaseColorSingleChannelEnabled()
111{
112 return m_material.isBaseColorSingleChannelEnabled();
113}
114
115bool QSSGShaderDefaultMaterialAdapter::isSpecularAmountSingleChannelEnabled()
116{
117 return m_material.isSpecularAmountSingleChannelEnabled();
118}
119
120bool QSSGShaderDefaultMaterialAdapter::isEmissiveSingleChannelEnabled()
121{
122 return m_material.isEmissiveSingleChannelEnabled();
123}
124
125bool QSSGShaderDefaultMaterialAdapter::isClearcoatEnabled()
126{
127 return m_material.isClearcoatEnabled();
128}
129
130bool QSSGShaderDefaultMaterialAdapter::isTransmissionEnabled()
131{
132 return m_material.isTransmissionEnabled();
133}
134
135bool QSSGShaderDefaultMaterialAdapter::hasLighting()
136{
137 return m_material.hasLighting();
138}
139
140bool QSSGShaderDefaultMaterialAdapter::usesCustomSkinning()
141{
142 return false;
143}
144
145bool QSSGShaderDefaultMaterialAdapter::usesCustomMorphing()
146{
147 return false;
148}
149
150QSSGRenderDefaultMaterial::MaterialSpecularModel QSSGShaderDefaultMaterialAdapter::specularModel()
151{
152 return m_material.specularModel;
153}
154
155QSSGRenderDefaultMaterial::MaterialAlphaMode QSSGShaderDefaultMaterialAdapter::alphaMode()
156{
157 return m_material.alphaMode;
158}
159
160QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderDefaultMaterialAdapter::vertexColorRedMask()
161{
162 return m_material.vertexColorRedMask;
163}
164
165QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderDefaultMaterialAdapter::vertexColorGreenMask()
166{
167 return m_material.vertexColorGreenMask;
168}
169
170QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderDefaultMaterialAdapter::vertexColorBlueMask()
171{
172 return m_material.vertexColorBlueMask;
173}
174
175QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderDefaultMaterialAdapter::vertexColorAlphaMask()
176{
177 return m_material.vertexColorAlphaMask;
178}
179
180QSSGRenderImage *QSSGShaderDefaultMaterialAdapter::iblProbe()
181{
182 return m_material.iblProbe;
183}
184
185QVector3D QSSGShaderDefaultMaterialAdapter::emissiveColor()
186{
187 return m_material.emissiveColor;
188}
189
190QVector4D QSSGShaderDefaultMaterialAdapter::color()
191{
192 return m_material.color;
193}
194
195QVector3D QSSGShaderDefaultMaterialAdapter::specularTint()
196{
197 return m_material.specularTint;
198}
199
200float QSSGShaderDefaultMaterialAdapter::ior()
201{
202 return m_material.ior;
203}
204
205bool QSSGShaderDefaultMaterialAdapter::isFresnelScaleBiasEnabled()
206{
207 return m_material.fresnelScaleBiasEnabled;
208}
209
210float QSSGShaderDefaultMaterialAdapter::fresnelScale()
211{
212 return m_material.fresnelScale;
213}
214
215float QSSGShaderDefaultMaterialAdapter::fresnelBias()
216{
217 return m_material.fresnelBias;
218}
219
220float QSSGShaderDefaultMaterialAdapter::fresnelPower()
221{
222 return m_material.fresnelPower;
223}
224
225bool QSSGShaderDefaultMaterialAdapter::isClearcoatFresnelScaleBiasEnabled()
226{
227 return m_material.clearcoatFresnelScaleBiasEnabled;
228}
229
230float QSSGShaderDefaultMaterialAdapter::clearcoatFresnelScale()
231{
232 return m_material.clearcoatFresnelScale;
233}
234
235float QSSGShaderDefaultMaterialAdapter::clearcoatFresnelBias()
236{
237 return m_material.clearcoatFresnelBias;
238}
239
240float QSSGShaderDefaultMaterialAdapter::clearcoatFresnelPower()
241{
242 return m_material.clearcoatFresnelPower;
243}
244
245float QSSGShaderDefaultMaterialAdapter::metalnessAmount()
246{
247 return m_material.metalnessAmount;
248}
249
250float QSSGShaderDefaultMaterialAdapter::specularAmount()
251{
252 return m_material.specularAmount;
253}
254
255float QSSGShaderDefaultMaterialAdapter::specularRoughness()
256{
257 return m_material.specularRoughness;
258}
259
260float QSSGShaderDefaultMaterialAdapter::bumpAmount()
261{
262 return m_material.bumpAmount;
263}
264
265float QSSGShaderDefaultMaterialAdapter::translucentFallOff()
266{
267 return m_material.translucentFalloff;
268}
269
270float QSSGShaderDefaultMaterialAdapter::diffuseLightWrap()
271{
272 return m_material.diffuseLightWrap;
273}
274
275float QSSGShaderDefaultMaterialAdapter::occlusionAmount()
276{
277 return m_material.occlusionAmount;
278}
279
280float QSSGShaderDefaultMaterialAdapter::alphaCutOff()
281{
282 return m_material.alphaCutoff;
283}
284
285float QSSGShaderDefaultMaterialAdapter::pointSize()
286{
287 return m_material.pointSize;
288}
289
290float QSSGShaderDefaultMaterialAdapter::lineWidth()
291{
292 return m_material.lineWidth;
293}
294
295float QSSGShaderDefaultMaterialAdapter::heightAmount()
296{
297 return m_material.heightAmount;
298}
299
300float QSSGShaderDefaultMaterialAdapter::minHeightSamples()
301{
302 return m_material.minHeightSamples;
303}
304
305float QSSGShaderDefaultMaterialAdapter::maxHeightSamples()
306{
307 return m_material.maxHeightSamples;
308}
309
310float QSSGShaderDefaultMaterialAdapter::clearcoatAmount()
311{
312 return m_material.clearcoatAmount;
313}
314
315float QSSGShaderDefaultMaterialAdapter::clearcoatRoughnessAmount()
316{
317 return m_material.clearcoatRoughnessAmount;
318}
319
320float QSSGShaderDefaultMaterialAdapter::clearcoatNormalStrength()
321{
322 return m_material.clearcoatNormalStrength;
323}
324
325float QSSGShaderDefaultMaterialAdapter::transmissionFactor()
326{
327 return m_material.transmissionFactor;
328}
329
330float QSSGShaderDefaultMaterialAdapter::thicknessFactor()
331{
332 return m_material.thicknessFactor;
333}
334
335float QSSGShaderDefaultMaterialAdapter::attenuationDistance()
336{
337 return m_material.attenuationDistance;
338}
339
340QVector3D QSSGShaderDefaultMaterialAdapter::attenuationColor()
341{
342 return m_material.attenuationColor;
343}
344
345QSSGShaderCustomMaterialAdapter::QSSGShaderCustomMaterialAdapter(const QSSGRenderCustomMaterial &material)
346 : m_material(material)
347{
348}
349
350// Act like Principled. Lighting is always on, specular, metalness, etc. support should all be enabled.
351// Unlike Principled, the *enabled values do not depend on the metalness or specularAmount values
352// (we cannot tell what those are if they are written in the shader).
353
354bool QSSGShaderCustomMaterialAdapter::isPrincipled()
355{
356 return true;
357}
358
359bool QSSGShaderCustomMaterialAdapter::isSpecularGlossy()
360{
361 return false;
362}
363
364bool QSSGShaderCustomMaterialAdapter::isMetalnessEnabled()
365{
366 return true;
367}
368
369bool QSSGShaderCustomMaterialAdapter::isSpecularEnabled()
370{
371 return true;
372}
373
374bool QSSGShaderCustomMaterialAdapter::isVertexColorsEnabled()
375{
376 return m_material.m_renderFlags.testFlag(flag: QSSGRenderCustomMaterial::RenderFlag::VarColor);
377}
378
379bool QSSGShaderCustomMaterialAdapter::isVertexColorsMaskEnabled()
380{
381 return false;
382}
383
384bool QSSGShaderCustomMaterialAdapter::isInvertOpacityMapValue()
385{
386 return false;
387}
388
389bool QSSGShaderCustomMaterialAdapter::isBaseColorSingleChannelEnabled()
390{
391 return false;
392}
393
394bool QSSGShaderCustomMaterialAdapter::isSpecularAmountSingleChannelEnabled()
395{
396 return false;
397}
398
399bool QSSGShaderCustomMaterialAdapter::isEmissiveSingleChannelEnabled()
400{
401 return false;
402}
403
404bool QSSGShaderCustomMaterialAdapter::isClearcoatEnabled()
405{
406 return m_material.m_renderFlags.testFlag(flag: QSSGRenderCustomMaterial::RenderFlag::Clearcoat);
407}
408
409bool QSSGShaderCustomMaterialAdapter::isTransmissionEnabled()
410{
411 return m_material.m_renderFlags.testFlag(flag: QSSGRenderCustomMaterial::RenderFlag::Transmission);
412}
413
414bool QSSGShaderCustomMaterialAdapter::hasLighting()
415{
416 return true;
417}
418
419bool QSSGShaderCustomMaterialAdapter::usesCustomSkinning()
420{
421 return m_material.m_renderFlags.testFlag(flag: QSSGRenderCustomMaterial::RenderFlag::Skinning);
422}
423
424bool QSSGShaderCustomMaterialAdapter::usesCustomMorphing()
425{
426 return m_material.m_renderFlags.testFlag(flag: QSSGRenderCustomMaterial::RenderFlag::Morphing);
427}
428
429QSSGRenderDefaultMaterial::MaterialSpecularModel QSSGShaderCustomMaterialAdapter::specularModel()
430{
431 return QSSGRenderDefaultMaterial::MaterialSpecularModel::Default;
432}
433
434QSSGRenderDefaultMaterial::MaterialAlphaMode QSSGShaderCustomMaterialAdapter::alphaMode()
435{
436 return QSSGRenderDefaultMaterial::MaterialAlphaMode::Default;
437}
438
439QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderCustomMaterialAdapter::vertexColorRedMask()
440{
441 return QSSGRenderDefaultMaterial::NoMask;
442}
443
444QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderCustomMaterialAdapter::vertexColorGreenMask()
445{
446 return QSSGRenderDefaultMaterial::NoMask;
447}
448
449QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderCustomMaterialAdapter::vertexColorBlueMask()
450{
451 return QSSGRenderDefaultMaterial::NoMask;
452}
453
454QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderCustomMaterialAdapter::vertexColorAlphaMask()
455{
456 return QSSGRenderDefaultMaterial::NoMask;
457}
458
459QSSGRenderImage *QSSGShaderCustomMaterialAdapter::iblProbe()
460{
461 return m_material.m_iblProbe;
462}
463
464// The following are the values that get set into uniforms such as
465// qt_material_properties etc. When a custom shader is present, these values
466// are not used at all. However, a CustomMaterial is also valid without a
467// vertex/fragment shader, or with no custom shaders at all. Therefore the
468// values here must match the defaults of PrincipledMaterial, in order to make
469// PrincipledMaterial { } and CustomMaterial { } identical.
470
471QVector3D QSSGShaderCustomMaterialAdapter::emissiveColor()
472{
473 return QVector3D(0, 0, 0);
474}
475
476QVector4D QSSGShaderCustomMaterialAdapter::color()
477{
478 return QVector4D(1, 1, 1, 1);
479}
480
481QVector3D QSSGShaderCustomMaterialAdapter::specularTint()
482{
483 return QVector3D(1, 1, 1);
484}
485
486float QSSGShaderCustomMaterialAdapter::ior()
487{
488 return 1.45f;
489}
490
491bool QSSGShaderCustomMaterialAdapter::isFresnelScaleBiasEnabled()
492{
493 return m_material.m_renderFlags.testFlag(flag: QSSGRenderCustomMaterial::RenderFlag::FresnelScaleBias);
494}
495
496float QSSGShaderCustomMaterialAdapter::fresnelScale()
497{
498 return 1.0f;
499}
500
501float QSSGShaderCustomMaterialAdapter::fresnelBias()
502{
503 return 0.0f;
504}
505
506float QSSGShaderCustomMaterialAdapter::fresnelPower()
507{
508 return 0.0f;
509}
510
511bool QSSGShaderCustomMaterialAdapter::isClearcoatFresnelScaleBiasEnabled()
512{
513 return m_material.m_renderFlags.testFlag(flag: QSSGRenderCustomMaterial::RenderFlag::ClearcoatFresnelScaleBias);
514}
515
516float QSSGShaderCustomMaterialAdapter::clearcoatFresnelScale()
517{
518 return 1.0f;
519}
520
521float QSSGShaderCustomMaterialAdapter::clearcoatFresnelBias()
522{
523 return 0.0f;
524}
525
526float QSSGShaderCustomMaterialAdapter::clearcoatFresnelPower()
527{
528 return 0.0f;
529}
530
531float QSSGShaderCustomMaterialAdapter::metalnessAmount()
532{
533 return 0.0f;
534}
535
536float QSSGShaderCustomMaterialAdapter::specularAmount()
537{
538 return 0.5f;
539}
540
541float QSSGShaderCustomMaterialAdapter::specularRoughness()
542{
543 return 0.0f;
544}
545
546float QSSGShaderCustomMaterialAdapter::bumpAmount()
547{
548 return 0.0f;
549}
550
551float QSSGShaderCustomMaterialAdapter::translucentFallOff()
552{
553 return 0.0f;
554}
555
556float QSSGShaderCustomMaterialAdapter::diffuseLightWrap()
557{
558 return 0.0f;
559}
560
561float QSSGShaderCustomMaterialAdapter::occlusionAmount()
562{
563 return 1.0f;
564}
565
566float QSSGShaderCustomMaterialAdapter::alphaCutOff()
567{
568 return 0.5f;
569}
570
571float QSSGShaderCustomMaterialAdapter::pointSize()
572{
573 return 1.0f;
574}
575
576float QSSGShaderCustomMaterialAdapter::lineWidth()
577{
578 return m_material.m_lineWidth;
579}
580
581float QSSGShaderCustomMaterialAdapter::heightAmount()
582{
583 return 0.0f;
584}
585
586float QSSGShaderCustomMaterialAdapter::minHeightSamples()
587{
588 return 0.0f;
589}
590
591float QSSGShaderCustomMaterialAdapter::maxHeightSamples()
592{
593 return 0.0f;
594}
595
596float QSSGShaderCustomMaterialAdapter::clearcoatAmount()
597{
598 return 0.0f;
599}
600
601float QSSGShaderCustomMaterialAdapter::clearcoatRoughnessAmount()
602{
603 return 0.0f;
604}
605
606float QSSGShaderCustomMaterialAdapter::clearcoatNormalStrength()
607{
608 return 1.0f;
609}
610
611float QSSGShaderCustomMaterialAdapter::transmissionFactor()
612{
613 return 0.0f;
614}
615
616float QSSGShaderCustomMaterialAdapter::thicknessFactor()
617{
618 return 0.0f;
619}
620
621float QSSGShaderCustomMaterialAdapter::attenuationDistance()
622{
623 return std::numeric_limits<float>::infinity();
624}
625
626QVector3D QSSGShaderCustomMaterialAdapter::attenuationColor()
627{
628 return { 1.0f, 1.0f, 1.0f };
629}
630
631bool QSSGShaderCustomMaterialAdapter::isUnshaded()
632{
633 return m_material.m_shadingMode == QSSGRenderCustomMaterial::ShadingMode::Unshaded;
634}
635
636bool QSSGShaderCustomMaterialAdapter::hasCustomShaderSnippet(QSSGShaderCache::ShaderType type)
637{
638 if (type == QSSGShaderCache::ShaderType::Vertex)
639 return m_material.m_customShaderPresence.testFlag(flag: QSSGRenderCustomMaterial::CustomShaderPresenceFlag::Vertex);
640
641 return m_material.m_customShaderPresence.testFlag(flag: QSSGRenderCustomMaterial::CustomShaderPresenceFlag::Fragment);
642}
643
644QByteArray QSSGShaderCustomMaterialAdapter::customShaderSnippet(QSSGShaderCache::ShaderType type,
645 QSSGShaderLibraryManager &shaderLibraryManager,
646 bool multiViewCompatible)
647{
648 if (hasCustomShaderSnippet(type)) {
649 const QByteArray shaderPathKey = m_material.m_shaderPathKey[multiViewCompatible ? QSSGRenderCustomMaterial::MultiViewShaderPathKeyIndex
650 : QSSGRenderCustomMaterial::RegularShaderPathKeyIndex];
651 return shaderLibraryManager.getShaderSource(inShaderPathKey: shaderPathKey, type);
652 }
653
654 return QByteArray();
655}
656
657bool QSSGShaderCustomMaterialAdapter::hasCustomShaderFunction(QSSGShaderCache::ShaderType shaderType,
658 const QByteArray &funcName,
659 QSSGShaderLibraryManager &shaderLibraryManager)
660{
661 if (hasCustomShaderSnippet(type: shaderType))
662 return shaderLibraryManager.getShaderMetaData(inShaderPathKey: m_material.m_shaderPathKey[QSSGRenderCustomMaterial::RegularShaderPathKeyIndex],
663 type: shaderType).customFunctions.contains(value: funcName);
664
665 return false;
666}
667
668void QSSGShaderCustomMaterialAdapter::setCustomPropertyUniforms(char *ubufData,
669 QSSGRhiShaderPipeline &shaderPipeline,
670 const QSSGRenderContextInterface &context)
671{
672 context.customMaterialSystem()->applyRhiShaderPropertyValues(ubufData, inMaterial: m_material, shaderPipeline);
673}
674
675bool QSSGShaderCustomMaterialAdapter::usesSharedVariables()
676{
677 return m_material.m_usesSharedVariables;
678}
679
680namespace {
681
682// Custom material shader substitution table.
683// Must be in sync with the shader generator.
684static const QSSGCustomMaterialVariableSubstitution qssg_var_subst_tab[] = {
685 // uniform (block members)
686 { .builtin: "MODELVIEWPROJECTION_MATRIX", .actualName: "qt_modelViewProjection", .multiViewDependent: true },
687 { .builtin: "VIEWPROJECTION_MATRIX", .actualName: "qt_viewProjectionMatrix", .multiViewDependent: true },
688 { .builtin: "MODEL_MATRIX", .actualName: "qt_modelMatrix", .multiViewDependent: false },
689 { .builtin: "VIEW_MATRIX", .actualName: "qt_viewMatrix", .multiViewDependent: true },
690 { .builtin: "NORMAL_MATRIX", .actualName: "qt_normalMatrix", .multiViewDependent: false },
691 { .builtin: "BONE_TRANSFORMS", .actualName: "qt_getTexMatrix", .multiViewDependent: false },
692 { .builtin: "BONE_NORMAL_TRANSFORMS", .actualName: "qt_getTexMatrix", .multiViewDependent: false },
693 { .builtin: "PROJECTION_MATRIX", .actualName: "qt_projectionMatrix", .multiViewDependent: true },
694 { .builtin: "INVERSE_PROJECTION_MATRIX", .actualName: "qt_inverseProjectionMatrix", .multiViewDependent: true },
695 { .builtin: "CAMERA_POSITION", .actualName: "qt_cameraPosition", .multiViewDependent: true },
696 { .builtin: "CAMERA_DIRECTION", .actualName: "qt_cameraDirection", .multiViewDependent: true },
697 { .builtin: "CAMERA_PROPERTIES", .actualName: "qt_cameraProperties", .multiViewDependent: false },
698 { .builtin: "FRAMEBUFFER_Y_UP", .actualName: "qt_rhi_properties.x", .multiViewDependent: false },
699 { .builtin: "NDC_Y_UP", .actualName: "qt_rhi_properties.y", .multiViewDependent: false },
700 { .builtin: "NEAR_CLIP_VALUE", .actualName: "qt_rhi_properties.z", .multiViewDependent: false },
701 { .builtin: "IBL_MAXMIPMAP", .actualName: "qt_lightProbeProperties.y", .multiViewDependent: false },
702 { .builtin: "IBL_HORIZON", .actualName: "qt_lightProbeProperties.z", .multiViewDependent: false },
703 { .builtin: "IBL_EXPOSE", .actualName: "qt_lightProbeProperties.w", .multiViewDependent: false },
704
705 // outputs
706 { .builtin: "POSITION", .actualName: "gl_Position", .multiViewDependent: false },
707 { .builtin: "FRAGCOLOR", .actualName: "fragOutput", .multiViewDependent: false },
708 { .builtin: "POINT_SIZE", .actualName: "gl_PointSize", .multiViewDependent: false },
709
710 // fragment inputs
711 { .builtin: "FRAGCOORD", .actualName: "gl_FragCoord", .multiViewDependent: false },
712
713 // functions
714 { .builtin: "DIRECTIONAL_LIGHT", .actualName: "qt_directionalLightProcessor", .multiViewDependent: false },
715 { .builtin: "POINT_LIGHT", .actualName: "qt_pointLightProcessor", .multiViewDependent: false },
716 { .builtin: "SPOT_LIGHT", .actualName: "qt_spotLightProcessor", .multiViewDependent: false },
717 { .builtin: "AMBIENT_LIGHT", .actualName: "qt_ambientLightProcessor", .multiViewDependent: false },
718 { .builtin: "SPECULAR_LIGHT", .actualName: "qt_specularLightProcessor", .multiViewDependent: false },
719 { .builtin: "MAIN", .actualName: "qt_customMain", .multiViewDependent: false },
720 { .builtin: "POST_PROCESS", .actualName: "qt_customPostProcessor", .multiViewDependent: false },
721 { .builtin: "IBL_PROBE", .actualName: "qt_iblProbeProcessor", .multiViewDependent: false },
722
723 // textures
724 { .builtin: "SCREEN_TEXTURE", .actualName: "qt_screenTexture", .multiViewDependent: true },
725 { .builtin: "SCREEN_MIP_TEXTURE", .actualName: "qt_screenTexture", .multiViewDependent: true }, // same resource as SCREEN_TEXTURE under the hood
726 { .builtin: "DEPTH_TEXTURE", .actualName: "qt_depthTexture", .multiViewDependent: true },
727 { .builtin: "AO_TEXTURE", .actualName: "qt_aoTexture", .multiViewDependent: true },
728 { .builtin: "IBL_TEXTURE", .actualName: "qt_lightProbe", .multiViewDependent: false },
729 { .builtin: "LIGHTMAP", .actualName: "qt_lightmap", .multiViewDependent: false },
730
731 // For shaded only: vertex outputs, for convenience and perf. (only those
732 // that are always present when lighting is enabled) The custom vertex main
733 // can also calculate on its own and pass them on with VARYING but that's a
734 // bit wasteful since we calculate these anyways.
735 { .builtin: "VAR_WORLD_NORMAL", .actualName: "qt_varNormal", .multiViewDependent: false },
736 { .builtin: "VAR_WORLD_TANGENT", .actualName: "qt_varTangent", .multiViewDependent: false },
737 { .builtin: "VAR_WORLD_BINORMAL", .actualName: "qt_varBinormal", .multiViewDependent: false },
738 { .builtin: "VAR_WORLD_POSITION", .actualName: "qt_varWorldPos", .multiViewDependent: false },
739 // vertex color is always enabled for custom materials (shaded)
740 { .builtin: "VAR_COLOR", .actualName: "qt_varColor", .multiViewDependent: false },
741
742 // effects
743 { .builtin: "INPUT", .actualName: "qt_inputTexture", .multiViewDependent: true },
744 { .builtin: "INPUT_UV", .actualName: "qt_inputUV", .multiViewDependent: false },
745 { .builtin: "TEXTURE_UV", .actualName: "qt_textureUV", .multiViewDependent: false },
746 { .builtin: "INPUT_SIZE", .actualName: "qt_inputSize", .multiViewDependent: false },
747 { .builtin: "OUTPUT_SIZE", .actualName: "qt_outputSize", .multiViewDependent: false },
748 { .builtin: "FRAME", .actualName: "qt_frame_num", .multiViewDependent: false },
749
750 // instancing
751 { .builtin: "INSTANCE_COLOR", .actualName: "qt_instanceColor", .multiViewDependent: false },
752 { .builtin: "INSTANCE_DATA", .actualName: "qt_instanceData", .multiViewDependent: false },
753 { .builtin: "INSTANCE_INDEX", .actualName: "gl_InstanceIndex", .multiViewDependent: false },
754
755 // morphing
756 { .builtin: "MORPH_POSITION", .actualName: "qt_getTargetPositionFromTargetId", .multiViewDependent: false },
757 { .builtin: "MORPH_NORMAL", .actualName: "qt_getTargetNormalFromTargetId", .multiViewDependent: false },
758 { .builtin: "MORPH_TANGENT", .actualName: "qt_getTargetTangentFromTargetId", .multiViewDependent: false },
759 { .builtin: "MORPH_BINORMAL", .actualName: "qt_getTargetBinormalFromTargetId", .multiViewDependent: false },
760 { .builtin: "MORPH_WEIGHTS", .actualName: "qt_morphWeights", .multiViewDependent: false },
761
762 // custom variables
763 { .builtin: "SHARED_VARS", .actualName: "struct QT_SHARED_VARS", .multiViewDependent: false },
764
765 // multiview
766 { .builtin: "VIEW_INDEX", .actualName: "qt_viewIndex", .multiViewDependent: false }
767};
768
769// Functions that, if present, get an argument list injected.
770static const QByteArrayView qssg_func_injectarg_tab[] = {
771 "DIRECTIONAL_LIGHT",
772 "POINT_LIGHT",
773 "SPOT_LIGHT",
774 "AMBIENT_LIGHT",
775 "SPECULAR_LIGHT",
776 "MAIN",
777 "POST_PROCESS",
778 "IBL_PROBE"
779};
780
781// This is based on the Qt Quick shader rewriter (with fixes)
782struct Tokenizer {
783 enum Token {
784 Token_Comment,
785 Token_OpenBrace,
786 Token_CloseBrace,
787 Token_OpenParen,
788 Token_CloseParen,
789 Token_SemiColon,
790 Token_Identifier,
791 Token_OpenBraket,
792 Token_CloseBraket,
793 Token_Unspecified,
794
795 Token_EOF
796 };
797
798 void initialize(const QByteArray &input);
799 Token next();
800
801 const char *stream;
802 const char *pos;
803 const char *identifier;
804};
805
806void Tokenizer::initialize(const QByteArray &input)
807{
808 stream = input.constData();
809 pos = input;
810 identifier = input;
811}
812
813Tokenizer::Token Tokenizer::next()
814{
815 while (*pos) {
816 char c = *pos++;
817 switch (c) {
818 case '/':
819 if (*pos == '/') {
820 // '//' comment
821 ++pos;
822 while (*pos && *pos != '\n') ++pos;
823 return Token_Comment;
824 } else if (*pos == '*') {
825 // /* */ comment
826 ++pos;
827 while (*pos && (*pos != '*' || pos[1] != '/')) ++pos;
828 if (*pos) pos += 2;
829 return Token_Comment;
830 }
831 return Token_Unspecified;
832
833 case ';': return Token_SemiColon;
834 case '\0': return Token_EOF;
835 case '{': return Token_OpenBrace;
836 case '}': return Token_CloseBrace;
837 case '(': return Token_OpenParen;
838 case ')': return Token_CloseParen;
839 case '[': return Token_OpenBraket;
840 case ']': return Token_CloseBraket;
841
842 case ' ':
843 case '\n':
844 case '\r': break;
845 default:
846 // Identifier...
847 if ((c >= 'a' && c <= 'z' ) || (c >= 'A' && c <= 'Z' ) || c == '_') {
848 identifier = pos - 1;
849 while (*pos && ((*pos >= 'a' && *pos <= 'z')
850 || (*pos >= 'A' && *pos <= 'Z')
851 || *pos == '_'
852 || (*pos >= '0' && *pos <= '9'))) {
853 ++pos;
854 }
855 return Token_Identifier;
856 } else {
857 return Token_Unspecified;
858 }
859 }
860 }
861
862 return Token_EOF;
863}
864} // namespace
865
866QSSGShaderCustomMaterialAdapter::ShaderCodeAndMetaData
867QSSGShaderCustomMaterialAdapter::prepareCustomShader(QByteArray &dst,
868 const QByteArray &shaderCode,
869 QSSGShaderCache::ShaderType type,
870 const StringPairList &baseUniforms,
871 const StringPairList &baseInputs,
872 const StringPairList &baseOutputs,
873 bool multiViewCompatible,
874 const StringPairList &multiViewDependentSamplers)
875{
876 QByteArrayList inputs;
877 QByteArrayList outputs;
878
879 Tokenizer tok;
880 tok.initialize(input: shaderCode);
881
882 QSSGCustomShaderMetaData md = {};
883 QByteArray result;
884 result.reserve(asize: 1024);
885 // If shader debugging is not enabled we reset the line count to make error message
886 // when a shader fails more useful. When shader debugging is enabled the whole shader
887 // will be printed and not just the user written part, so in that case we do not want
888 // to adjust the line numbers.
889 //
890 // NOTE: This is not perfect, we do expend the custom material and effect shaders, so
891 // there cane still be cases where the reported line numbers are slightly off.
892 if (!QSSGRhiContextPrivate::shaderDebuggingEnabled())
893 result.prepend(s: "#line 1\n");
894 const char *lastPos = shaderCode.constData();
895
896 int funcFinderState = 0;
897 int useJointTexState = -1;
898 int useJointNormalTexState = -1;
899 QByteArray currentShadedFunc;
900 Tokenizer::Token t = tok.next();
901 while (t != Tokenizer::Token_EOF) {
902 switch (t) {
903 case Tokenizer::Token_Comment:
904 break;
905 case Tokenizer::Token_Identifier:
906 {
907 QByteArray id = QByteArray::fromRawData(data: lastPos, size: tok.pos - lastPos);
908 if (id.trimmed() == QByteArrayLiteral("VARYING")) {
909 QByteArray vtype;
910 QByteArray vname;
911 bool vflat = false;
912 lastPos = tok.pos;
913 t = tok.next();
914 while (t != Tokenizer::Token_EOF) {
915 QByteArray data = QByteArray::fromRawData(data: lastPos, size: tok.pos - lastPos);
916 if (t == Tokenizer::Token_Identifier) {
917 if (vtype.isEmpty()) {
918 vtype = data.trimmed();
919 if (vtype == QByteArrayLiteral("flat")) {
920 vflat = true;
921 vtype.clear();
922 }
923 } else if (vname.isEmpty()) {
924 vname = data.trimmed();
925 }
926 }
927 if (t == Tokenizer::Token_SemiColon)
928 break;
929 lastPos = tok.pos;
930 t = tok.next();
931 }
932 if (type == QSSGShaderCache::ShaderType::Vertex)
933 outputs.append(t: (vflat ? "flat " : "") + vtype + " " + vname);
934 else
935 inputs.append(t: (vflat ? "flat " : "") + vtype + " " + vname);
936 } else {
937 const QByteArray trimmedId = id.trimmed();
938 if (funcFinderState == 0 && trimmedId == QByteArrayLiteral("void")) {
939 funcFinderState += 1;
940 } else if (funcFinderState == 1) {
941 auto begin = qssg_func_injectarg_tab;
942 const auto end = qssg_func_injectarg_tab + (sizeof(qssg_func_injectarg_tab) / sizeof(qssg_func_injectarg_tab[0]));
943 const auto foundIt = std::find_if(first: begin, last: end, pred: [trimmedId](const QByteArrayView &entry) { return entry == trimmedId; });
944 if (foundIt != end) {
945 currentShadedFunc = trimmedId;
946 funcFinderState += 1;
947 }
948 } else {
949 funcFinderState = 0;
950 }
951
952 if (trimmedId == QByteArrayLiteral("SCREEN_TEXTURE"))
953 md.flags |= QSSGCustomShaderMetaData::UsesScreenTexture;
954 else if (trimmedId == QByteArrayLiteral("SCREEN_MIP_TEXTURE"))
955 md.flags |= QSSGCustomShaderMetaData::UsesScreenMipTexture;
956 else if (trimmedId == QByteArrayLiteral("DEPTH_TEXTURE"))
957 md.flags |= QSSGCustomShaderMetaData::UsesDepthTexture;
958 else if (trimmedId == QByteArrayLiteral("AO_TEXTURE"))
959 md.flags |= QSSGCustomShaderMetaData::UsesAoTexture;
960 else if (trimmedId == QByteArrayLiteral("POSITION"))
961 md.flags |= QSSGCustomShaderMetaData::OverridesPosition;
962 else if (trimmedId == QByteArrayLiteral("PROJECTION_MATRIX"))
963 md.flags |= QSSGCustomShaderMetaData::UsesProjectionMatrix;
964 else if (trimmedId == QByteArrayLiteral("INVERSE_PROJECTION_MATRIX"))
965 md.flags |= QSSGCustomShaderMetaData::UsesInverseProjectionMatrix;
966 else if (trimmedId == QByteArrayLiteral("VAR_COLOR"))
967 md.flags |= QSSGCustomShaderMetaData::UsesVarColor;
968 else if (trimmedId == QByteArrayLiteral("SHARED_VARS"))
969 md.flags |= QSSGCustomShaderMetaData::UsesSharedVars;
970 else if (trimmedId == QByteArrayLiteral("IBL_ORIENTATION"))
971 md.flags |= QSSGCustomShaderMetaData::UsesIblOrientation;
972 else if (trimmedId == QByteArrayLiteral("LIGHTMAP"))
973 md.flags |= QSSGCustomShaderMetaData::UsesLightmap;
974 else if (trimmedId == QByteArrayLiteral("VIEW_INDEX"))
975 md.flags |= QSSGCustomShaderMetaData::UsesViewIndex;
976 else if (trimmedId == QByteArrayLiteral("INPUT"))
977 md.flags |= QSSGCustomShaderMetaData::UsesInputTexture;
978 else if (trimmedId == QByteArrayLiteral("CLEARCOAT_AMOUNT"))
979 md.flags |= QSSGCustomShaderMetaData::UsesClearcoat;
980 else if (trimmedId == QByteArrayLiteral("CLEARCOAT_FRESNEL_SCALE") ||
981 trimmedId == QByteArrayLiteral("CLEARCOAT_FRESNEL_BIAS"))
982 md.flags |= QSSGCustomShaderMetaData::UsesClearcoatFresnelScaleBias;
983 else if (trimmedId == QByteArrayLiteral("FRESNEL_SCALE") ||
984 trimmedId == QByteArrayLiteral("FRESNEL_BIAS"))
985 md.flags |= QSSGCustomShaderMetaData::UsesFresnelScaleBias;
986 else if (trimmedId == QByteArrayLiteral("TRANSMISSION_FACTOR")) {
987 md.flags |= QSSGCustomShaderMetaData::UsesTransmission;
988 md.flags |= QSSGCustomShaderMetaData::UsesScreenTexture;
989 md.flags |= QSSGCustomShaderMetaData::UsesScreenMipTexture;
990 }
991
992 for (const QSSGCustomMaterialVariableSubstitution &subst : qssg_var_subst_tab) {
993 if (trimmedId == subst.builtin) {
994 QByteArray newExpr;
995 newExpr.assign(v: subst.actualName);
996 if (subst.multiViewDependent && multiViewCompatible) {
997 if (subst.builtin.endsWith(QByteArrayLiteral("_TEXTURE"))
998 || subst.builtin == QByteArrayLiteral("INPUT"))
999 {
1000 newExpr += QByteArrayLiteral("Array"); // e.g. qt_depthTexture -> qt_depthTextureArray
1001 } else {
1002 newExpr += QByteArrayLiteral("[qt_viewIndex]"); // e.g. qt_viewProjectionMatrix -> qt_viewProjectionMatrix[qt_viewIndex]
1003 }
1004 }
1005 id.replace(before: subst.builtin, after: newExpr); // replace, not assignment, to keep whitespace etc.
1006 if (trimmedId == QByteArrayLiteral("BONE_TRANSFORMS")) {
1007 useJointTexState = 0;
1008 md.flags |= QSSGCustomShaderMetaData::UsesSkinning;
1009 } else if (trimmedId == QByteArrayLiteral("BONE_NORMAL_TRANSFORMS")) {
1010 useJointNormalTexState = 0;
1011 md.flags |= QSSGCustomShaderMetaData::UsesSkinning;
1012 }
1013 if (trimmedId == QByteArrayLiteral("MORPH_POSITION") ||
1014 trimmedId == QByteArrayLiteral("MORPH_NORMAL") ||
1015 trimmedId == QByteArrayLiteral("MORPH_TANGENT") ||
1016 trimmedId == QByteArrayLiteral("MORPH_BINORMAL"))
1017 md.flags |= QSSGCustomShaderMetaData::UsesMorphing;
1018 break;
1019 }
1020 }
1021 result += id;
1022 }
1023 }
1024 break;
1025 case Tokenizer::Token_OpenParen:
1026 result += QByteArray::fromRawData(data: lastPos, size: tok.pos - lastPos);
1027 if (funcFinderState == 2) {
1028 result += QByteArrayLiteral("/*%QT_ARGS_");
1029 result += currentShadedFunc;
1030 result += QByteArrayLiteral("%*/");
1031 for (const QSSGCustomMaterialVariableSubstitution &subst : qssg_var_subst_tab) {
1032 if (currentShadedFunc == subst.builtin) {
1033 currentShadedFunc = subst.actualName.toByteArray();
1034 break;
1035 }
1036 }
1037 md.customFunctions.insert(value: currentShadedFunc);
1038 currentShadedFunc.clear();
1039 }
1040 funcFinderState = 0;
1041 break;
1042 case Tokenizer::Token_OpenBraket:
1043 // copy everything as-is up to the [
1044 result += QByteArray::fromRawData(data: lastPos, size: tok.pos - lastPos - 1);
1045 if (useJointTexState == 0) {
1046 result += QByteArrayLiteral("(2 * (");
1047 ++useJointTexState;
1048 break;
1049 } else if (useJointNormalTexState == 0) {
1050 result += QByteArrayLiteral("(1 + 2 * (");
1051 ++useJointNormalTexState;
1052 break;
1053 }
1054
1055 if (useJointTexState >= 0)
1056 ++useJointTexState;
1057 else if (useJointNormalTexState >= 0)
1058 ++useJointNormalTexState;
1059 result += QByteArrayLiteral("[");
1060 break;
1061 case Tokenizer::Token_CloseBraket:
1062 // copy everything as-is up to the ]
1063 result += QByteArray::fromRawData(data: lastPos, size: tok.pos - lastPos - 1);
1064 // This implementation will not allow mixed usages of BONE_TRANSFORMS and
1065 // BONE_NORMAL_TRANSFORMS.
1066 // For example, BONE_TRANSFORM[int(BONE_NORMAL_TRANFORMS[i][0].x)]
1067 // cannot be compiled successfully.
1068 if (useJointTexState <= 0 && useJointNormalTexState <= 0) {
1069 result += QByteArrayLiteral("]");
1070 break;
1071 }
1072 if (useJointTexState > 1) {
1073 result += QByteArrayLiteral("]");
1074 --useJointTexState;
1075 break;
1076 } else if (useJointNormalTexState > 1) {
1077 result += QByteArrayLiteral("]");
1078 --useJointNormalTexState;
1079 break;
1080 }
1081 result += QByteArrayLiteral("))");
1082 useJointTexState = -1;
1083 useJointNormalTexState = -1;
1084 break;
1085 default:
1086 result += QByteArray::fromRawData(data: lastPos, size: tok.pos - lastPos);
1087 break;
1088 }
1089 lastPos = tok.pos;
1090 t = tok.next();
1091 }
1092
1093 result += '\n';
1094
1095 StringPairList allUniforms = baseUniforms;
1096
1097 for (const StringPair &samplerTypeAndName : multiViewDependentSamplers) {
1098 if (multiViewCompatible)
1099 allUniforms.append(t: { "sampler2DArray", samplerTypeAndName.second });
1100 else
1101 allUniforms.append(t: samplerTypeAndName);
1102 }
1103
1104 // We either have qt_depthTexture or qt_depthTextureArray (or none of them),
1105 // but never both. We do not generally support binding a 2D texture to a
1106 // sampler2DArray binding point and vice versa. Therefore it is up to the
1107 // shader snippet to ifdef with QSHADER_VIEW_COUNT if it wants to support
1108 // both multiview and non-multiview rendering.
1109 if (md.flags.testFlag(flag: QSSGCustomShaderMetaData::UsesDepthTexture)) {
1110 if (multiViewCompatible)
1111 allUniforms.append(t: { "sampler2DArray", "qt_depthTextureArray" });
1112 else
1113 allUniforms.append(t: { "sampler2D", "qt_depthTexture" });
1114 }
1115
1116 // And the same pattern for qt_screenTexture(Array).
1117 if ((md.flags.testFlag(flag: QSSGCustomShaderMetaData::UsesScreenTexture) || md.flags.testFlag(flag: QSSGCustomShaderMetaData::UsesScreenMipTexture))) {
1118 if (multiViewCompatible)
1119 allUniforms.append(t: { "sampler2DArray", "qt_screenTextureArray" });
1120 else
1121 allUniforms.append(t: { "sampler2D", "qt_screenTexture" });
1122 }
1123
1124 // And for SSAO.
1125 if (md.flags.testFlag(flag: QSSGCustomShaderMetaData::UsesAoTexture)) {
1126 if (multiViewCompatible)
1127 allUniforms.append(t: { "sampler2DArray", "qt_aoTextureArray" });
1128 else
1129 allUniforms.append(t: { "sampler2D", "qt_aoTexture" });
1130 }
1131
1132 // Input texture for post-processing effects.
1133 if (md.flags.testFlag(flag: QSSGCustomShaderMetaData::UsesInputTexture)) {
1134 if (multiViewCompatible)
1135 allUniforms.append(t: { "sampler2DArray", "qt_inputTextureArray" });
1136 else
1137 allUniforms.append(t: { "sampler2D", "qt_inputTexture" });
1138 }
1139
1140 if (md.flags.testFlag(flag: QSSGCustomShaderMetaData::UsesLightmap))
1141 allUniforms.append(t: { "sampler2D", "qt_lightmap" });
1142
1143 static const char *metaStart = "#ifdef QQ3D_SHADER_META\n/*{\n \"uniforms\": [\n";
1144 static const char *metaEnd = " ]\n}*/\n#endif\n";
1145 dst.append(s: metaStart);
1146 for (int i = 0, count = allUniforms.size(); i < count; ++i) {
1147 const auto &typeAndName(allUniforms[i]);
1148 dst.append(a: " { \"type\": \"" + typeAndName.first + "\", \"name\": \"" + typeAndName.second + "\" }");
1149 if (i < count - 1)
1150 dst.append(s: ",");
1151 dst.append(s: "\n");
1152 }
1153 dst.append(s: metaEnd);
1154
1155 const char *stageStr = type == QSSGShaderCache::ShaderType::Vertex ? "vertex" : "fragment";
1156 StringPairList allInputs = baseInputs;
1157 QVarLengthArray<bool, 16> inputIsFlat(allInputs.count(), false);
1158 for (const QByteArray &inputTypeAndName : inputs) {
1159 const QByteArrayList typeAndName = inputTypeAndName.split(sep: ' ');
1160 if (typeAndName.size() == 2) {
1161 allInputs.append(t: { typeAndName[0].trimmed(), typeAndName[1].trimmed() });
1162 inputIsFlat.append(t: false);
1163 } else if (typeAndName.size() == 3 && typeAndName[0].startsWith(bv: "flat")) {
1164 allInputs.append(t: { typeAndName[1].trimmed(), typeAndName[2].trimmed() });
1165 inputIsFlat.append(t: true);
1166 }
1167 }
1168 if (!allInputs.isEmpty()) {
1169 static const char *metaStart = "#ifdef QQ3D_SHADER_META\n/*{\n \"inputs\": [\n";
1170 static const char *metaEnd = " ]\n}*/\n#endif\n";
1171 dst.append(s: metaStart);
1172 for (int i = 0, count = allInputs.size(); i < count; ++i) {
1173 dst.append(a: " { \"type\": \"" + allInputs[i].first
1174 + "\", \"name\": \"" + allInputs[i].second
1175 + "\", \"stage\": \"" + stageStr
1176 + (inputIsFlat[i] ? "\", \"flat\": true" : "\"")
1177 + " }");
1178 if (i < count - 1)
1179 dst.append(s: ",");
1180 dst.append(s: "\n");
1181 }
1182 dst.append(s: metaEnd);
1183 }
1184
1185 StringPairList allOutputs = baseOutputs;
1186 QVarLengthArray<bool, 16> outputIsFlat(allOutputs.count(), false);
1187 for (const QByteArray &outputTypeAndName : outputs) {
1188 const QByteArrayList typeAndName = outputTypeAndName.split(sep: ' ');
1189 if (typeAndName.size() == 2) {
1190 allOutputs.append(t: { typeAndName[0].trimmed(), typeAndName[1].trimmed() });
1191 outputIsFlat.append(t: false);
1192 } else if (typeAndName.size() == 3 && typeAndName[0].startsWith(bv: "flat")) {
1193 allOutputs.append(t: { typeAndName[1].trimmed(), typeAndName[2].trimmed() });
1194 outputIsFlat.append(t: true);
1195 }
1196 }
1197 if (!allOutputs.isEmpty()) {
1198 static const char *metaStart = "#ifdef QQ3D_SHADER_META\n/*{\n \"outputs\": [\n";
1199 static const char *metaEnd = " ]\n}*/\n#endif\n";
1200 dst.append(s: metaStart);
1201 for (int i = 0, count = allOutputs.size(); i < count; ++i) {
1202 dst.append(a: " { \"type\": \"" + allOutputs[i].first
1203 + "\", \"name\": \"" + allOutputs[i].second
1204 + "\", \"stage\": \"" + stageStr
1205 + (outputIsFlat[i] ? "\", \"flat\": true" : "\"")
1206 + " }");
1207 if (i < count - 1)
1208 dst.append(s: ",");
1209 dst.append(s: "\n");
1210 }
1211 dst.append(s: metaEnd);
1212 }
1213
1214 return { result, md };
1215}
1216
1217QList<QByteArrayView> QtQuick3DEditorHelpers::CustomMaterial::preprocessorVars()
1218{
1219 QList<QByteArrayView> k;
1220 k.reserve(asize: std::size(qssg_var_subst_tab));
1221 for (const auto &v : qssg_var_subst_tab)
1222 k.push_back(t: v.builtin);
1223 return k;
1224}
1225
1226QT_END_NAMESPACE
1227
1228

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtquick3d/src/runtimerender/qssgshadermaterialadapter.cpp