File indexing completed on 2024-05-12 15:42:40

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "shadowedrectanglematerial.h"
0008 
0009 #include <QOpenGLContext>
0010 
0011 QSGMaterialType ShadowedRectangleMaterial::staticType;
0012 
0013 ShadowedRectangleMaterial::ShadowedRectangleMaterial()
0014 {
0015     setFlag(QSGMaterial::Blending, true);
0016 }
0017 
0018 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0019 QSGMaterialShader *ShadowedRectangleMaterial::createShader() const
0020 #else
0021 QSGMaterialShader *ShadowedRectangleMaterial::createShader(QSGRendererInterface::RenderMode) const
0022 #endif
0023 {
0024     return new ShadowedRectangleShader{shaderType};
0025 }
0026 
0027 QSGMaterialType *ShadowedRectangleMaterial::type() const
0028 {
0029     return &staticType;
0030 }
0031 
0032 int ShadowedRectangleMaterial::compare(const QSGMaterial *other) const
0033 {
0034     auto material = static_cast<const ShadowedRectangleMaterial *>(other);
0035     /* clang-format off */
0036     if (material->color == color
0037         && material->shadowColor == shadowColor
0038         && material->offset == offset
0039         && material->aspect == aspect
0040         && qFuzzyCompare(material->size, size)
0041         && qFuzzyCompare(material->radius, radius)) { /* clang-format on */
0042         return 0;
0043     }
0044 
0045     return QSGMaterial::compare(other);
0046 }
0047 
0048 ShadowedRectangleShader::ShadowedRectangleShader(ShadowedRectangleMaterial::ShaderType shaderType)
0049 {
0050     setShader(shaderType, QStringLiteral("shadowedrectangle"));
0051 }
0052 
0053 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0054 const char *const *ShadowedRectangleShader::attributeNames() const
0055 {
0056     static char const *const names[] = {"in_vertex", "in_uv", nullptr};
0057     return names;
0058 }
0059 
0060 void ShadowedRectangleShader::initialize()
0061 {
0062     QSGMaterialShader::initialize();
0063     m_matrixLocation = program()->uniformLocation("matrix");
0064     m_aspectLocation = program()->uniformLocation("aspect");
0065     m_opacityLocation = program()->uniformLocation("opacity");
0066     m_sizeLocation = program()->uniformLocation("size");
0067     m_radiusLocation = program()->uniformLocation("radius");
0068     m_colorLocation = program()->uniformLocation("color");
0069     m_shadowColorLocation = program()->uniformLocation("shadowColor");
0070     m_offsetLocation = program()->uniformLocation("offset");
0071 }
0072 
0073 void ShadowedRectangleShader::updateState(const QSGMaterialShader::RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
0074 {
0075     auto p = program();
0076 
0077     if (state.isMatrixDirty()) {
0078         p->setUniformValue(m_matrixLocation, state.combinedMatrix());
0079     }
0080 
0081     if (state.isOpacityDirty()) {
0082         p->setUniformValue(m_opacityLocation, state.opacity());
0083     }
0084 
0085     if (!oldMaterial || newMaterial->compare(oldMaterial) != 0 || state.isCachedMaterialDataDirty()) {
0086         auto material = static_cast<ShadowedRectangleMaterial *>(newMaterial);
0087         p->setUniformValue(m_aspectLocation, material->aspect);
0088         p->setUniformValue(m_sizeLocation, material->size);
0089         p->setUniformValue(m_radiusLocation, material->radius);
0090         p->setUniformValue(m_colorLocation, material->color);
0091         p->setUniformValue(m_shadowColorLocation, material->shadowColor);
0092         p->setUniformValue(m_offsetLocation, material->offset);
0093     }
0094 }
0095 #else
0096 bool ShadowedRectangleShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
0097 {
0098     bool changed = false;
0099     QByteArray *buf = state.uniformData();
0100     Q_ASSERT(buf->size() >= 160);
0101 
0102     if (state.isMatrixDirty()) {
0103         const QMatrix4x4 m = state.combinedMatrix();
0104         memcpy(buf->data(), m.constData(), 64);
0105         changed = true;
0106     }
0107 
0108     if (state.isOpacityDirty()) {
0109         const float opacity = state.opacity();
0110         memcpy(buf->data() + 72, &opacity, 4);
0111         changed = true;
0112     }
0113 
0114     if (!oldMaterial || newMaterial->compare(oldMaterial) != 0) {
0115         const auto material = static_cast<ShadowedRectangleMaterial *>(newMaterial);
0116         memcpy(buf->data() + 64, &material->aspect, 8);
0117         memcpy(buf->data() + 76, &material->size, 4);
0118         memcpy(buf->data() + 80, &material->radius, 16);
0119         float c[4];
0120         material->color.getRgbF(&c[0], &c[1], &c[2], &c[3]);
0121         memcpy(buf->data() + 96, c, 16);
0122         material->shadowColor.getRgbF(&c[0], &c[1], &c[2], &c[3]);
0123         memcpy(buf->data() + 112, c, 16);
0124         memcpy(buf->data() + 128, &material->offset, 8);
0125         changed = true;
0126     }
0127 
0128     return changed;
0129 }
0130 #endif
0131 
0132 void ShadowedRectangleShader::setShader(ShadowedRectangleMaterial::ShaderType shaderType, const QString &shader)
0133 {
0134     const auto shaderRoot = QStringLiteral(":/org/kde/kirigami/shaders/");
0135 
0136 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0137     auto header = QOpenGLContext::currentContext()->isOpenGLES() ? QStringLiteral("header_es.glsl") : QStringLiteral("header_desktop.glsl");
0138 
0139     setShaderSourceFiles(QOpenGLShader::Vertex, {shaderRoot + header, shaderRoot + QStringLiteral("shadowedrectangle.vert")});
0140 
0141     QString shaderFile = shader + QStringLiteral(".frag");
0142     auto sdfFile = QStringLiteral("sdf.glsl");
0143     if (shaderType == ShadowedRectangleMaterial::ShaderType::LowPower) {
0144         shaderFile = shader + QStringLiteral("_lowpower.frag");
0145         sdfFile = QStringLiteral("sdf_lowpower.glsl");
0146     }
0147 
0148     setShaderSourceFiles(QOpenGLShader::Fragment, {shaderRoot + header, shaderRoot + sdfFile, shaderRoot + shaderFile});
0149 #else
0150     setShaderFileName(QSGMaterialShader::VertexStage, shaderRoot + QStringLiteral("shadowedrectangle.vert.qsb"));
0151 
0152     auto shaderFile = shader;
0153     if (shaderType == ShadowedRectangleMaterial::ShaderType::LowPower) {
0154         shaderFile += QStringLiteral("_lowpower");
0155     }
0156     setShaderFileName(QSGMaterialShader::FragmentStage, shaderRoot + shaderFile + QStringLiteral(".frag.qsb"));
0157 #endif
0158 }