1 /*
2 SPDX-FileCopyrightText: 2014 David Edmundson <davidedmundson@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
7 #include "fadingnode_p.h"
8
9 #include <QOpenGLContext>
10 #include <QOpenGLFunctions>
11 #include <QSGSimpleMaterialShader>
12
13 struct FadingMaterialState {
14 QSGTexture *source = nullptr;
15 QSGTexture *target = nullptr;
16 qreal progress;
17 };
18
19 class FadingMaterialShader : public QSGSimpleMaterialShader<FadingMaterialState>
20 {
21 QSG_DECLARE_SIMPLE_SHADER(FadingMaterialShader, FadingMaterialState)
22 public:
23 FadingMaterialShader();
24 using QSGSimpleMaterialShader<FadingMaterialState>::updateState;
25 void updateState(const FadingMaterialState *newState, const FadingMaterialState *oldState) override;
26 QList<QByteArray> attributes() const override;
27
28 void initialize() override;
29
30 private:
31 QOpenGLFunctions *glFuncs = nullptr;
32 int m_progressId = 0;
33 int m_sourceRectId = 0;
34 int m_targetRectId = 0;
35 };
36
FadingMaterialShader()37 FadingMaterialShader::FadingMaterialShader()
38 {
39 setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/plasma-framework/shaders/fadingmaterial.frag"));
40 setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/plasma-framework/shaders/fadingmaterial.vert"));
41 }
42
attributes() const43 QList<QByteArray> FadingMaterialShader::attributes() const
44 {
45 return {QByteArrayLiteral("qt_Vertex"), QByteArrayLiteral("qt_MultiTexCoord0")};
46 }
47
updateState(const FadingMaterialState * newState,const FadingMaterialState * oldState)48 void FadingMaterialShader::updateState(const FadingMaterialState *newState, const FadingMaterialState *oldState)
49 {
50 if (!oldState || oldState->source != newState->source) {
51 glFuncs->glActiveTexture(GL_TEXTURE0);
52 newState->source->bind();
53 QRectF rect = newState->source->normalizedTextureSubRect();
54 program()->setUniformValue(m_sourceRectId, QVector4D(rect.x(), rect.y(), rect.width(), rect.height()));
55 }
56
57 if (!oldState || oldState->target != newState->target) {
58 glFuncs->glActiveTexture(GL_TEXTURE1);
59 newState->target->bind();
60 QRectF rect = newState->target->normalizedTextureSubRect();
61 program()->setUniformValue(m_targetRectId, QVector4D(rect.x(), rect.y(), rect.width(), rect.height()));
62 // reset the active texture back to 0 after we changed it to something else
63 glFuncs->glActiveTexture(GL_TEXTURE0);
64 }
65
66 if (!oldState || oldState->progress != newState->progress) {
67 program()->setUniformValue(m_progressId, (GLfloat)newState->progress);
68 }
69 }
70
initialize()71 void FadingMaterialShader::initialize()
72 {
73 if (!program()->isLinked()) {
74 // shader not linked, exit otherwise we crash, BUG: 336272
75 return;
76 }
77 QSGSimpleMaterialShader<FadingMaterialState>::initialize();
78 glFuncs = QOpenGLContext::currentContext()->functions();
79 program()->bind();
80 program()->setUniformValue("u_src", 0);
81 program()->setUniformValue("u_target", 1);
82
83 m_progressId = program()->uniformLocation("u_transitionProgress");
84 m_sourceRectId = program()->uniformLocation("u_src_rect");
85 m_targetRectId = program()->uniformLocation("u_target_rect");
86 }
87
FadingNode(QSGTexture * source,QSGTexture * target)88 FadingNode::FadingNode(QSGTexture *source, QSGTexture *target)
89 : m_source(source)
90 , m_target(target)
91 {
92 QSGSimpleMaterial<FadingMaterialState> *m = FadingMaterialShader::createMaterial();
93 m->setFlag(QSGMaterial::Blending);
94 setMaterial(m);
95 setFlag(OwnsMaterial, true);
96 setProgress(1.0);
97
98 QSGGeometry *g = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
99 QSGGeometry::updateTexturedRectGeometry(g, QRect(), QRect());
100 setGeometry(g);
101 setFlag(QSGNode::OwnsGeometry, true);
102 }
103
~FadingNode()104 FadingNode::~FadingNode()
105 {
106 }
107
setRect(const QRectF & bounds)108 void FadingNode::setRect(const QRectF &bounds)
109 {
110 QSGGeometry::updateTexturedRectGeometry(geometry(), bounds, QRectF(0, 0, 1, 1));
111 markDirty(QSGNode::DirtyGeometry);
112 }
113
setProgress(qreal progress)114 void FadingNode::setProgress(qreal progress)
115 {
116 QSGSimpleMaterial<FadingMaterialState> *m = static_cast<QSGSimpleMaterial<FadingMaterialState> *>(material());
117 m->state()->source = m_source.data();
118 m->state()->target = m_target.data();
119 m->state()->progress = progress;
120 markDirty(QSGNode::DirtyMaterial);
121 }
122