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