902void QQuickMultiEffect::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
904 Q_D(QQuickMultiEffect);
905 QQuickItem::geometryChange(newGeometry, oldGeometry);
906 if (width() > 0 && height() > 0)
907 d->handleGeometryChange(newGeometry, oldGeometry);
1005void QQuickMultiEffectPrivate::setBrightness(qreal brightness)
1007 Q_Q(QQuickMultiEffect);
1008 if (brightness == m_brightness)
1011 m_brightness = brightness;
1013 m_shaderEffect->setProperty(
"brightness", m_brightness);
1016 Q_EMIT q->brightnessChanged();
1043void QQuickMultiEffectPrivate::setSaturation(qreal saturation)
1045 Q_Q(QQuickMultiEffect);
1046 if (saturation == m_saturation)
1049 m_saturation = saturation;
1051 m_shaderEffect->setProperty(
"saturation", m_saturation);
1054 Q_EMIT q->saturationChanged();
1062void QQuickMultiEffectPrivate::setColorization(qreal colorization)
1064 Q_Q(QQuickMultiEffect);
1065 if (colorization == m_colorization)
1068 m_colorization = colorization;
1069 updateColorizationColor();
1072 Q_EMIT q->colorizationChanged();
1080void QQuickMultiEffectPrivate::setColorizationColor(
const QColor &color)
1082 Q_Q(QQuickMultiEffect);
1083 if (color == m_colorizationColor)
1086 m_colorizationColor = color;
1087 updateColorizationColor();
1090 Q_EMIT q->colorizationColorChanged();
1159void QQuickMultiEffectPrivate::setBlurMultiplier(qreal blurMultiplier)
1161 Q_Q(QQuickMultiEffect);
1162 if (blurMultiplier == m_blurMultiplier)
1165 m_blurMultiplier = blurMultiplier;
1166 updateSourcePadding();
1167 updateBlurItemSizes(
true);
1168 updateBlurWeights();
1169 updateShadowBlurWeights();
1172 Q_EMIT q->blurMultiplierChanged();
1218void QQuickMultiEffectPrivate::setShadowBlur(qreal shadowBlur)
1220 Q_Q(QQuickMultiEffect);
1221 if (shadowBlur == m_shadowBlur)
1224 m_shadowBlur = shadowBlur;
1225 updateShadowBlurWeights();
1228 Q_EMIT q->shadowBlurChanged();
1290void QQuickMultiEffectPrivate::setShadowScale(qreal shadowScale)
1292 Q_Q(QQuickMultiEffect);
1293 if (shadowScale == m_shadowScale)
1296 m_shadowScale = shadowScale;
1297 updateCenterOffset();
1299 m_shaderEffect->setProperty(
"shadowScale", 1.0 / m_shadowScale);
1302 Q_EMIT q->shadowScaleChanged();
1328void QQuickMultiEffectPrivate::setMaskSource(QQuickItem *item)
1330 Q_Q(QQuickMultiEffect);
1331 if (item == m_maskSourceItem)
1334 m_maskSourceItem = item;
1335 if (m_shaderEffect) {
1336 auto maskSourceVariant = QVariant::fromValue<QQuickItem*>(m_maskSourceItem);
1337 m_shaderEffect->setProperty(
"maskSrc", maskSourceVariant);
1341 Q_EMIT q->maskSourceChanged();
1349void QQuickMultiEffectPrivate::setMaskThresholdMin(qreal threshold)
1351 Q_Q(QQuickMultiEffect);
1352 if (threshold == m_maskThresholdMin)
1355 m_maskThresholdMin = threshold;
1356 updateMaskThresholdSpread();
1359 Q_EMIT q->maskThresholdMinChanged();
1367void QQuickMultiEffectPrivate::setMaskSpreadAtMin(qreal spread)
1369 Q_Q(QQuickMultiEffect);
1370 if (spread == m_maskSpreadAtMin)
1373 m_maskSpreadAtMin = spread;
1374 updateMaskThresholdSpread();
1377 Q_EMIT q->maskSpreadAtMinChanged();
1385void QQuickMultiEffectPrivate::setMaskThresholdMax(qreal threshold)
1387 Q_Q(QQuickMultiEffect);
1388 if (threshold == m_maskThresholdMax)
1391 m_maskThresholdMax = threshold;
1392 updateMaskThresholdSpread();
1395 Q_EMIT q->maskThresholdMaxChanged();
1403void QQuickMultiEffectPrivate::setMaskSpreadAtMax(qreal spread)
1405 Q_Q(QQuickMultiEffect);
1406 if (spread == m_maskSpreadAtMax)
1409 m_maskSpreadAtMax = spread;
1410 updateMaskThresholdSpread();
1413 Q_EMIT q->maskSpreadAtMaxChanged();
1421void QQuickMultiEffectPrivate::setMaskInverted(
bool inverted)
1423 Q_Q(QQuickMultiEffect);
1424 if (inverted == m_maskInverted)
1427 m_maskInverted = inverted;
1429 m_shaderEffect->setProperty(
"maskInverted",
float(m_maskInverted));
1432 Q_EMIT q->maskInvertedChanged();
1435QRectF QQuickMultiEffectPrivate::itemRect()
const
1437 if (!m_shaderEffect || !m_shaderSource)
1440 QRectF sourceRect = m_shaderSource->sourceRect();
1441 if (sourceRect.width() > 0 && sourceRect.height() > 0)
1444 return m_shaderEffect->boundingRect();
1464void QQuickMultiEffectPrivate::initialize()
1466 Q_Q(QQuickMultiEffect);
1469 if (!q->isComponentComplete())
1473 if (q->width() <= 0 || q->height() <= 0)
1476 m_shaderEffect =
new QQuickShaderEffect(q);
1477 m_shaderSource =
new QGfxSourceProxyME(q);
1478 QObject::connect(m_shaderSource, &QGfxSourceProxyME::outputChanged, q, [
this] { proxyOutputChanged(); });
1479 QObject::connect(m_shaderSource, &QGfxSourceProxyME::activeChanged, q, &QQuickMultiEffect::hasProxySourceChanged);
1481 m_shaderEffect->setParentItem(q);
1482 m_shaderEffect->setSize(q->size());
1484 m_shaderSource->setParentItem(q);
1485 m_shaderSource->setSize(q->size());
1486 m_shaderSource->setInput(m_sourceItem);
1488 updateCenterOffset();
1489 updateMaskThresholdSpread();
1490 updateBlurWeights();
1491 updateShadowBlurWeights();
1492 updateColorizationColor();
1493 updateShadowColor();
1494 updateShadowOffset();
1497 auto sourceVariant = QVariant::fromValue<QQuickItem*>(m_shaderSource->output());
1498 m_shaderEffect->setProperty(
"src", sourceVariant);
1499 m_shaderEffect->setProperty(
"brightness", m_brightness);
1500 m_shaderEffect->setProperty(
"contrast", m_contrast);
1501 m_shaderEffect->setProperty(
"saturation", m_saturation);
1502 m_shaderEffect->setProperty(
"shadowScale", 1.0 / m_shadowScale);
1503 auto maskSourceVariant = QVariant::fromValue<QQuickItem*>(m_maskSourceItem);
1504 m_shaderEffect->setProperty(
"maskSrc", maskSourceVariant);
1505 m_shaderEffect->setProperty(
"maskInverted",
float(m_maskInverted));
1508 updateBlurItemSizes();
1509 updateSourcePadding();
1511 updateEffectShaders();
1513 m_initialized =
true;
1516void QQuickMultiEffectPrivate::updateMaskThresholdSpread()
1518 if (!m_shaderEffect)
1523 const qreal c0 = 0.0001;
1524 const qreal c1 = 1.0 - c0;
1525 const qreal mt1 = m_maskThresholdMin + c0;
1526 const qreal ms1 = m_maskSpreadAtMin + 1.0;
1527 const qreal mt2 = c1 - m_maskThresholdMax;
1528 const qreal ms2 = m_maskSpreadAtMax + 1.0;
1529 const QVector4D maskThresholdSpread = QVector4D(
1530 mt1 * ms1 - (ms1 - c1),
1532 mt2 * ms2 - (ms2 - c1),
1534 m_shaderEffect->setProperty(
"mask", maskThresholdSpread);
1537void QQuickMultiEffectPrivate::updateCenterOffset()
1539 if (!m_shaderEffect)
1542 const qreal scale = 1.0 / m_shadowScale;
1543 QVector2D centerOffset((1.0 - scale) * (0.5 + 0.5 * (m_paddingRect.x() - m_paddingRect.width()) / m_shaderEffect->width()),
1544 (1.0 - scale) * (0.5 + 0.5 * (m_paddingRect.y() - m_paddingRect.height()) / m_shaderEffect->height()));
1545 m_shaderEffect->setProperty(
"centerOffset", centerOffset);
1557void QQuickMultiEffectPrivate::updateColorizationColor()
1559 if (!m_shaderEffect)
1562 float alpha = std::clamp(
float(m_colorizationColor.alphaF() * m_colorization), 0.0f, 1.0f);
1563 QVector4D colorizationColor(m_colorizationColor.redF(),
1564 m_colorizationColor.greenF(),
1565 m_colorizationColor.blueF(),
1567 m_shaderEffect->setProperty(
"colorizationColor", colorizationColor);
1570void QQuickMultiEffectPrivate::updateShadowColor()
1572 if (!m_shaderEffect)
1576 float alpha = std::clamp(
float(m_shadowOpacity), 0.0f, 1.0f);
1577 QVector4D shadowColor(m_shadowColor.redF() * alpha,
1578 m_shadowColor.greenF() * alpha,
1579 m_shadowColor.blueF() * alpha,
1580 m_shadowColor.alphaF() * alpha);
1581 m_shaderEffect->setProperty(
"shadowColor", shadowColor);
1594void QQuickMultiEffectPrivate::getBlurWeights(
float blurLod, QVector4D &blurWeight1, QVector2D &blurWeight2)
1596 float bw1 = blurWeight(std::fabs(blurLod - 0.1f));
1597 float bw2 = blurWeight(std::fabs(blurLod - 0.3f));
1598 float bw3 = blurWeight(std::fabs(blurLod - 0.5f));
1599 float bw4 = blurWeight(std::fabs(blurLod - 0.7f));
1600 float bw5 = blurWeight(std::fabs(blurLod - 0.9f));
1601 float bw6 = blurWeight(std::fabs(blurLod - 1.1f));
1602 float bsum = bw1 + bw2 + bw3 + bw4 + bw5 + bw6;
1603 blurWeight1 = QVector4D(bw1 / bsum, bw2 / bsum, bw3 / bsum, bw4 / bsum);
1604 blurWeight2 = QVector2D(bw5 / bsum, bw6 / bsum);
1607void QQuickMultiEffectPrivate::updateBlurWeights()
1609 if (!m_shaderEffect)
1611 float blurLod = calculateLod(m_blur);
1612 getBlurWeights(blurLod, m_blurWeight1, m_blurWeight2);
1613 m_shaderEffect->setProperty(
"blurWeight1", m_blurWeight1);
1614 m_shaderEffect->setProperty(
"blurWeight2", m_blurWeight2);
1617void QQuickMultiEffectPrivate::updateShadowBlurWeights()
1619 if (!m_shaderEffect)
1621 float blurLod = calculateLod(m_shadowBlur);
1622 getBlurWeights(blurLod, m_shadowBlurWeight1, m_shadowBlurWeight2);
1623 m_shaderEffect->setProperty(
"shadowBlurWeight1", m_shadowBlurWeight1);
1624 m_shaderEffect->setProperty(
"shadowBlurWeight2", m_shadowBlurWeight2);
1627void QQuickMultiEffectPrivate::updateBlurItemSizes(
bool forceUpdate)
1629 if (m_blurEffects.isEmpty() || !m_shaderSource || !m_sourceItem)
1634 QSizeF sourceSize = itemRect().size();
1635 QSizeF firstItemSize(std::ceil(sourceSize.width() / 16) * 8,
1636 std::ceil(sourceSize.height() / 16) * 8);
1638 if (!forceUpdate && m_firstBlurItemSize == firstItemSize)
1641 qCDebug(lcQuickEffect) <<
"Source size:" << sourceSize;
1642 m_firstBlurItemSize = firstItemSize;
1644 for (
int i = 0; i < m_blurEffects.size(); i++) {
1645 auto *blurEffect = m_blurEffects[i];
1646 QSizeF itemSize = (i == 0) ? firstItemSize : m_blurEffects[i - 1]->size() * 0.5;
1647 qCDebug(lcQuickEffect) <<
"Blur item" << i <<
":" << itemSize;
1648 blurEffect->setSize(itemSize);
1650 const QVector2D offset((1.0 + m_blurMultiplier) / itemSize.width(),
1651 (1.0 + m_blurMultiplier) / itemSize.height());
1652 blurEffect->setProperty(
"offset", offset);
1656void QQuickMultiEffectPrivate::updateEffectShaders()
1658 Q_Q(QQuickMultiEffect);
1659 if (!q->isComponentComplete() || !m_shaderEffect)
1662 QString vShader = QStringLiteral(
"multieffect_c");
1663 if (m_shadowEnabled)
1664 vShader += QStringLiteral(
"s");
1666 QString fShader = QStringLiteral(
"multieffect_c");
1668 fShader += QStringLiteral(
"m");
1669 if (m_blurEnabled && m_blurMax > 0)
1670 fShader += QStringLiteral(
"b");
1671 if (m_shadowEnabled)
1672 fShader += QStringLiteral(
"s");
1674 fShader += QString::number(m_blurLevel);
1676 bool shaderChanged =
false;
1677 if (fShader != m_fragShader) {
1678 shaderChanged =
true;
1679 m_fragShader = fShader;
1680 QUrl fs = QUrl(QStringLiteral(
"qrc:/data/shaders/%1.frag.qsb").arg(m_fragShader));
1681 m_shaderEffect->setFragmentShader(fs);
1682 Q_EMIT q->fragmentShaderChanged();
1684 if (vShader != m_vertShader) {
1685 shaderChanged =
true;
1686 m_vertShader = vShader;
1687 QUrl vs = QUrl(QStringLiteral(
"qrc:/data/shaders/%1.vert.qsb").arg(m_vertShader));
1688 m_shaderEffect->setVertexShader(vs);
1689 Q_EMIT q->vertexShaderChanged();
1691 if (shaderChanged) {
1692 qCDebug(lcQuickEffect) <<
this <<
"Shaders: " << m_fragShader << m_vertShader;
1693 Q_EMIT q->shaderChanged();
1697void QQuickMultiEffectPrivate::updateBlurLevel(
bool forceUpdate)
1700 if ((m_blurEnabled || m_shadowEnabled) && m_blurMax > 0) {
1703 else if (m_blurMax > 16)
1709 if (blurLevel != m_blurLevel || (blurLevel > 0 && m_blurEffects.isEmpty()) || forceUpdate) {
1712 updateBlurItemsAmount(blurLevel);
1714 if (blurLevel > m_blurLevel)
1715 updateBlurItemSizes(
true);
1717 m_blurLevel = blurLevel;
1720void QQuickMultiEffectPrivate::updateBlurItemsAmount(
int blurLevel)
1722 Q_Q(QQuickMultiEffect);
1723 if (!m_shaderEffect)
1726 const auto engine = qmlEngine(q);
1731 int itemsAmount = blurLevel == 0 ? 0 : blurLevel + 2;
1733 if (m_blurEffects.size() < itemsAmount) {
1737 QUrl blurVs = QUrl(QStringLiteral(
"qrc:/data/shaders/bluritems.vert.qsb"));
1738 QUrl blurFs = QUrl(QStringLiteral(
"qrc:/data/shaders/bluritems.frag.qsb"));
1739 QQmlComponent blurComponent(
1741 QUrl(QStringLiteral(
"qrc:/qt-project.org/imports/QtQuick/Effects/BlurItem.qml")));
1742 for (
int i = m_blurEffects.size(); i < itemsAmount; i++) {
1743 auto blurEffect = qobject_cast<QQuickShaderEffect*>(blurComponent.create());
1744 blurEffect->setParent(q);
1745 blurEffect->setParentItem(q);
1746 auto sourceVariant = QVariant::fromValue<QQuickItem*>(blurEffect);
1747 QString sourceProperty = QStringLiteral(
"blurSrc%1").arg(i + 1);
1748 m_shaderEffect->setProperty(sourceProperty.toUtf8(), sourceVariant);
1751 blurEffect->setProperty(
"source", sourceVariant);
1752 QQuickItemPrivate *priv = QQuickItemPrivate::get(blurEffect);
1753 priv->layer()->setEnabled(
true);
1754 priv->layer()->setSmooth(
true);
1755 blurEffect->setVertexShader(blurVs);
1756 blurEffect->setFragmentShader(blurFs);
1757 m_blurEffects << blurEffect;
1762 if (!m_dummyShaderSource)
1763 m_dummyShaderSource =
new QQuickShaderEffectSource(q);
1764 for (
int i = 0; i < m_blurEffects.size(); i++) {
1765 auto *blurEffect = m_blurEffects[i];
1766 auto sourceItem = (i >= itemsAmount) ?
1767 static_cast<QQuickItem *>(m_dummyShaderSource) : (i == 0) ?
1768 static_cast<QQuickItem *>(m_shaderSource->output()) :
1769 static_cast<QQuickItem *>(m_blurEffects[i - 1]);
1770 auto sourceVariant = QVariant::fromValue<QQuickItem*>(sourceItem);
1771 blurEffect->setProperty(
"source", sourceVariant);
1775void QQuickMultiEffectPrivate::updateSourcePadding()
1777 Q_Q(QQuickMultiEffect);
1778 if (!m_shaderEffect || !m_shaderSource)
1781 const bool blurItemsNeeded = (m_blurEnabled || m_shadowEnabled) && (m_blurMax > 0);
1782 const int itemPadding = m_autoPaddingEnabled && blurItemsNeeded ? m_blurMax * (1.0 + m_blurMultiplier) : 0;
1785 if (m_paddingRect != QRectF() || itemPadding > 0) {
1786 QRectF effectRect(-m_paddingRect.x() - itemPadding,
1787 -m_paddingRect.y() - itemPadding,
1788 q->width() + m_paddingRect.x() + m_paddingRect.width() + (itemPadding * 2),
1789 q->height() + m_paddingRect.y() + m_paddingRect.height() + (itemPadding * 2));
1790 m_shaderEffect->setX(effectRect.x());
1791 m_shaderEffect->setY(effectRect.y());
1792 m_shaderEffect->setWidth(effectRect.width());
1793 m_shaderEffect->setHeight(effectRect.height());
1796 m_shaderSource->setSize(m_shaderEffect->size());
1801 const qreal baseWidth = m_sourceItem && m_sourceItem->width() > 0 ? m_sourceItem->width() : q->width();
1802 const qreal baseHeight = m_sourceItem && m_sourceItem->height() > 0 ? m_sourceItem->height() : q->height();
1805 const qreal widthMultiplier = q->width() > 0 ? baseWidth / q->width() : 1.0;
1806 const qreal heightMultiplier = q->height() > 0 ? baseHeight / q->height() : 1.0;
1807 const qreal xPadding = itemPadding * widthMultiplier;
1808 const qreal yPadding = itemPadding * heightMultiplier;
1809 QRectF rect = QRectF(m_paddingRect.x() * widthMultiplier,
1810 m_paddingRect.y() * heightMultiplier,
1811 m_paddingRect.width() * widthMultiplier,
1812 m_paddingRect.height() * heightMultiplier);
1813 QRectF sourceRect = QRectF(-rect.x() - xPadding,
1814 -rect.y() - yPadding,
1815 baseWidth + rect.x() + rect.width() + xPadding * 2,
1816 baseHeight + rect.y() + rect.height() + yPadding * 2);
1817 m_shaderSource->setSourceRect(sourceRect);
1819 m_shaderEffect->setX(0);
1820 m_shaderEffect->setY(0);
1821 m_shaderEffect->setSize(q->size());
1822 m_shaderSource->setSize(q->size());
1823 m_shaderSource->setSourceRect(QRectF());
1826 updateShadowOffset();
1827 updateProxyActiveCheck();
1828 updateBlurItemSizes();
1829 Q_EMIT q->paddingRectChanged();
1830 Q_EMIT q->itemRectChanged();
1831 Q_EMIT q->itemSizeChanged();