1 | // Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "scene3dsgmaterialshader_p.h" |
5 | |
6 | #include <qopenglcontext.h> |
7 | #include <qopenglfunctions.h> |
8 | #include <QtGui/qsurfaceformat.h> |
9 | |
10 | #include <scene3dsgmaterial_p.h> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | namespace { |
15 | |
16 | inline bool isPowerOfTwo(int x) |
17 | { |
18 | // Assumption: x >= 1 |
19 | return x == (x & -x); |
20 | } |
21 | |
22 | } |
23 | |
24 | namespace Qt3DRender { |
25 | |
26 | /*! |
27 | \class Qt3DCore::SCene3DMaterialShader |
28 | \internal |
29 | |
30 | \brief The Qt3DRender::Scene3DSGMaterialShader class is a custom |
31 | QSGMaterialShader subclass instantiated by a Qt3DRender::Scene3DSGMateria1 |
32 | |
33 | The Qt3DRender::Scene3DSGMaterialShader provides a shader that renders a texture |
34 | using premultiplied alpha. |
35 | */ |
36 | |
37 | QSGMaterialType Scene3DSGMaterialShader::type; |
38 | |
39 | Scene3DSGMaterialShader::Scene3DSGMaterialShader() |
40 | : QSGMaterialShader() |
41 | { |
42 | // Generated with qsb, we target all GL version Qt3D can handle |
43 | // qsb -b --glsl "460,450,440,430,420,410,400,330,150,120,320 es,300 es,100 es" --hlsl 50 --msl 12 -o scene3dmaterial.vert.qsb scene3dmaterial.vert |
44 | // qsb --glsl "460,450,440,430,420,410,400,330,150,120,320 es,300 es,100 es" --hlsl 50 --msl 12 -o scene3dmaterial.frag.qsb scene3dmaterial.frag |
45 | setShaderFileName(stage: VertexStage, filename: QLatin1String(":/shaders/scene3dmaterial.vert.qsb" )); |
46 | setShaderFileName(stage: FragmentStage, filename: QLatin1String(":/shaders/scene3dmaterial.frag.qsb" )); |
47 | } |
48 | |
49 | bool Scene3DSGMaterialShader::updateUniformData(QSGMaterialShader::RenderState &state, |
50 | QSGMaterial *newMaterial, |
51 | QSGMaterial *oldMaterial) |
52 | { |
53 | // layout(std140, binding = 0) uniform buf { |
54 | // mat4 qt_Matrix; // offset 0, sizeof(float) * 16 |
55 | // float qt_Opacity; // offset sizeof(float) * 16, sizeof(float) |
56 | // bool visible; // offset sizeof(float) * 17, sizeof(float) |
57 | // }; |
58 | |
59 | QByteArray *buf = state.uniformData(); |
60 | Q_ASSERT(buf->size() >= int(18 * sizeof(float))); |
61 | Scene3DSGMaterial *tx = static_cast<Scene3DSGMaterial *>(newMaterial); |
62 | Scene3DSGMaterial *oldTx = static_cast<Scene3DSGMaterial *>(oldMaterial); |
63 | |
64 | bool updateMade = false; |
65 | |
66 | if (state.isMatrixDirty()) { |
67 | const QMatrix4x4 &m = state.combinedMatrix(); |
68 | memcpy(dest: buf->data(), src: m.constData(), n: 16 * sizeof(float)); |
69 | updateMade = true; |
70 | } |
71 | |
72 | if (state.isOpacityDirty()) { |
73 | const float opacity = state.opacity(); |
74 | memcpy(dest: buf->data() + 16 * sizeof(float), src: &opacity, n: sizeof(float)); |
75 | updateMade = true; |
76 | } |
77 | |
78 | if (oldTx == nullptr || oldTx->visible() != tx->visible()) { |
79 | const float value = tx->visible() ? 1.0f : -1.0f; |
80 | memcpy(dest: buf->data() + 17 * sizeof(float), src: &value, n: sizeof(float)); |
81 | updateMade = true; |
82 | } |
83 | |
84 | return updateMade; |
85 | } |
86 | |
87 | void Scene3DSGMaterialShader::updateSampledImage(QSGMaterialShader::RenderState &state, |
88 | int binding, |
89 | QSGTexture **texture, |
90 | QSGMaterial *newMaterial, |
91 | QSGMaterial *oldMaterial) |
92 | { |
93 | Q_UNUSED(state); |
94 | Q_UNUSED(binding); |
95 | Scene3DSGMaterial *tx = static_cast<Scene3DSGMaterial *>(newMaterial); |
96 | Scene3DSGMaterial *oldTx = static_cast<Scene3DSGMaterial *>(oldMaterial); |
97 | QSGTexture *t = tx->texture(); |
98 | |
99 | if (t != nullptr) { |
100 | // TODO QT6 FIXME |
101 | // bool npotSupported = const_cast<QOpenGLContext *>(state.context()) |
102 | // ->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat); |
103 | bool npotSupported = true; |
104 | if (!npotSupported) { |
105 | const QSize size = t->textureSize(); |
106 | const bool isNpot = !isPowerOfTwo(x: size.width()) || !isPowerOfTwo(x: size.height()); |
107 | if (isNpot) { |
108 | t->setHorizontalWrapMode(QSGTexture::ClampToEdge); |
109 | t->setVerticalWrapMode(QSGTexture::ClampToEdge); |
110 | } |
111 | } |
112 | |
113 | if (oldTx == nullptr || oldTx->texture() != t) |
114 | *texture = t; |
115 | } |
116 | } |
117 | |
118 | } // namespace Qt3DRender |
119 | |
120 | QT_END_NAMESPACE |
121 | |