File indexing completed on 2024-04-28 03:56:00
0001 /* 0002 * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "shadowedrectanglenode.h" 0008 #include "shadowedborderrectanglematerial.h" 0009 0010 QColor premultiply(const QColor &color) 0011 { 0012 return QColor::fromRgbF(color.redF() * color.alphaF(), // 0013 color.greenF() * color.alphaF(), 0014 color.blueF() * color.alphaF(), 0015 color.alphaF()); 0016 } 0017 0018 ShadowedRectangleNode::ShadowedRectangleNode() 0019 { 0020 m_geometry = new QSGGeometry{QSGGeometry::defaultAttributes_TexturedPoint2D(), 4}; 0021 setGeometry(m_geometry); 0022 0023 setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); 0024 } 0025 0026 void ShadowedRectangleNode::setBorderEnabled(bool enabled) 0027 { 0028 // We can achieve more performant shaders by splitting the two into separate 0029 // shaders. This requires separating the materials as well. So when 0030 // borderWidth is increased to something where the border should be visible, 0031 // switch to the with-border material. Otherwise use the no-border version. 0032 0033 if (enabled) { 0034 if (!m_material || m_material->type() == borderlessMaterialType()) { 0035 auto newMaterial = createBorderMaterial(); 0036 newMaterial->shaderType = m_shaderType; 0037 setMaterial(newMaterial); 0038 m_material = newMaterial; 0039 m_rect = QRectF{}; 0040 markDirty(QSGNode::DirtyMaterial); 0041 } 0042 } else { 0043 if (!m_material || m_material->type() == borderMaterialType()) { 0044 auto newMaterial = createBorderlessMaterial(); 0045 newMaterial->shaderType = m_shaderType; 0046 setMaterial(newMaterial); 0047 m_material = newMaterial; 0048 m_rect = QRectF{}; 0049 markDirty(QSGNode::DirtyMaterial); 0050 } 0051 } 0052 } 0053 0054 void ShadowedRectangleNode::setRect(const QRectF &rect) 0055 { 0056 if (rect == m_rect) { 0057 return; 0058 } 0059 0060 m_rect = rect; 0061 0062 QVector2D newAspect{1.0, 1.0}; 0063 if (m_rect.width() >= m_rect.height()) { 0064 newAspect.setX(m_rect.width() / m_rect.height()); 0065 } else { 0066 newAspect.setY(m_rect.height() / m_rect.width()); 0067 } 0068 0069 if (m_material->aspect != newAspect) { 0070 m_material->aspect = newAspect; 0071 markDirty(QSGNode::DirtyMaterial); 0072 m_aspect = newAspect; 0073 } 0074 } 0075 0076 void ShadowedRectangleNode::setSize(qreal size) 0077 { 0078 auto minDimension = std::min(m_rect.width(), m_rect.height()); 0079 float uniformSize = (size / minDimension) * 2.0; 0080 0081 if (!qFuzzyCompare(m_material->size, uniformSize)) { 0082 m_material->size = uniformSize; 0083 markDirty(QSGNode::DirtyMaterial); 0084 m_size = size; 0085 } 0086 } 0087 0088 void ShadowedRectangleNode::setRadius(const QVector4D &radius) 0089 { 0090 float minDimension = std::min(m_rect.width(), m_rect.height()); 0091 auto uniformRadius = QVector4D{std::min(radius.x() * 2.0f / minDimension, 1.0f), 0092 std::min(radius.y() * 2.0f / minDimension, 1.0f), 0093 std::min(radius.z() * 2.0f / minDimension, 1.0f), 0094 std::min(radius.w() * 2.0f / minDimension, 1.0f)}; 0095 0096 if (m_material->radius != uniformRadius) { 0097 m_material->radius = uniformRadius; 0098 markDirty(QSGNode::DirtyMaterial); 0099 m_radius = radius; 0100 } 0101 } 0102 0103 void ShadowedRectangleNode::setColor(const QColor &color) 0104 { 0105 auto premultiplied = premultiply(color); 0106 if (m_material->color != premultiplied) { 0107 m_material->color = premultiplied; 0108 markDirty(QSGNode::DirtyMaterial); 0109 } 0110 } 0111 0112 void ShadowedRectangleNode::setShadowColor(const QColor &color) 0113 { 0114 auto premultiplied = premultiply(color); 0115 if (m_material->shadowColor != premultiplied) { 0116 m_material->shadowColor = premultiplied; 0117 markDirty(QSGNode::DirtyMaterial); 0118 } 0119 } 0120 0121 void ShadowedRectangleNode::setOffset(const QVector2D &offset) 0122 { 0123 auto minDimension = std::min(m_rect.width(), m_rect.height()); 0124 auto uniformOffset = offset / minDimension; 0125 0126 if (m_material->offset != uniformOffset) { 0127 m_material->offset = uniformOffset; 0128 markDirty(QSGNode::DirtyMaterial); 0129 m_offset = offset; 0130 } 0131 } 0132 0133 void ShadowedRectangleNode::setBorderWidth(qreal width) 0134 { 0135 if (m_material->type() != borderMaterialType()) { 0136 return; 0137 } 0138 0139 auto minDimension = std::min(m_rect.width(), m_rect.height()); 0140 float uniformBorderWidth = width / minDimension; 0141 0142 auto borderMaterial = static_cast<ShadowedBorderRectangleMaterial *>(m_material); 0143 if (!qFuzzyCompare(borderMaterial->borderWidth, uniformBorderWidth)) { 0144 borderMaterial->borderWidth = uniformBorderWidth; 0145 markDirty(QSGNode::DirtyMaterial); 0146 m_borderWidth = width; 0147 } 0148 } 0149 0150 void ShadowedRectangleNode::setBorderColor(const QColor &color) 0151 { 0152 if (m_material->type() != borderMaterialType()) { 0153 return; 0154 } 0155 0156 auto borderMaterial = static_cast<ShadowedBorderRectangleMaterial *>(m_material); 0157 auto premultiplied = premultiply(color); 0158 if (borderMaterial->borderColor != premultiplied) { 0159 borderMaterial->borderColor = premultiplied; 0160 markDirty(QSGNode::DirtyMaterial); 0161 } 0162 } 0163 0164 void ShadowedRectangleNode::setShaderType(ShadowedRectangleMaterial::ShaderType type) 0165 { 0166 m_shaderType = type; 0167 } 0168 0169 void ShadowedRectangleNode::updateGeometry() 0170 { 0171 auto rect = m_rect; 0172 if (m_shaderType == ShadowedRectangleMaterial::ShaderType::Standard) { 0173 rect = rect.adjusted(-m_size * m_aspect.x(), // 0174 -m_size * m_aspect.y(), 0175 m_size * m_aspect.x(), 0176 m_size * m_aspect.y()); 0177 0178 auto offsetLength = m_offset.length(); 0179 rect = rect.adjusted(-offsetLength * m_aspect.x(), // 0180 -offsetLength * m_aspect.y(), 0181 offsetLength * m_aspect.x(), 0182 offsetLength * m_aspect.y()); 0183 } 0184 0185 QSGGeometry::updateTexturedRectGeometry(m_geometry, rect, QRectF{0.0, 0.0, 1.0, 1.0}); 0186 markDirty(QSGNode::DirtyGeometry); 0187 } 0188 0189 ShadowedRectangleMaterial *ShadowedRectangleNode::createBorderlessMaterial() 0190 { 0191 return new ShadowedRectangleMaterial{}; 0192 } 0193 0194 ShadowedBorderRectangleMaterial *ShadowedRectangleNode::createBorderMaterial() 0195 { 0196 return new ShadowedBorderRectangleMaterial{}; 0197 } 0198 0199 QSGMaterialType *ShadowedRectangleNode::borderlessMaterialType() 0200 { 0201 return &ShadowedRectangleMaterial::staticType; 0202 } 0203 0204 QSGMaterialType *ShadowedRectangleNode::borderMaterialType() 0205 { 0206 return &ShadowedBorderRectangleMaterial::staticType; 0207 }