218QQuickMultiEffect::~QQuickMultiEffect()
220 Q_D(QQuickMultiEffect);
226 if (d->m_sourceItem) {
227 QQuickItemPrivate::get(d->m_sourceItem)
228 ->removeItemChangeListener(d, QQuickItemPrivate::ChangeType::Destroyed);
230 if (d->m_maskSourceItem) {
231 QQuickItemPrivate::get(d->m_maskSourceItem)
232 ->removeItemChangeListener(d, QQuickItemPrivate::ChangeType::Destroyed);
916void QQuickMultiEffect::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
918 Q_D(QQuickMultiEffect);
919 QQuickItem::geometryChange(newGeometry, oldGeometry);
920 if (width() > 0 && height() > 0)
921 d->handleGeometryChange(newGeometry, oldGeometry);
965void QQuickMultiEffectPrivate::setSource(QQuickItem *item)
967 Q_Q(QQuickMultiEffect);
968 if (item == m_sourceItem)
972 QQuickItemPrivate::get(m_sourceItem)->removeItemChangeListener(
this, ChangeType::Destroyed);
974 QQuickItemPrivate::get(item)->addItemChangeListener(
this, ChangeType::Destroyed);
978 m_shaderSource->setInput(m_sourceItem);
980 updateSourcePadding();
982 Q_EMIT q->sourceChanged();
1024void QQuickMultiEffectPrivate::setBrightness(qreal brightness)
1026 Q_Q(QQuickMultiEffect);
1027 if (brightness == m_brightness)
1030 m_brightness = brightness;
1032 m_shaderEffect->setProperty(
"brightness", m_brightness);
1035 Q_EMIT q->brightnessChanged();
1062void QQuickMultiEffectPrivate::setSaturation(qreal saturation)
1064 Q_Q(QQuickMultiEffect);
1065 if (saturation == m_saturation)
1068 m_saturation = saturation;
1070 m_shaderEffect->setProperty(
"saturation", m_saturation);
1073 Q_EMIT q->saturationChanged();
1081void QQuickMultiEffectPrivate::setColorization(qreal colorization)
1083 Q_Q(QQuickMultiEffect);
1084 if (colorization == m_colorization)
1087 m_colorization = colorization;
1088 updateColorizationColor();
1091 Q_EMIT q->colorizationChanged();
1099void QQuickMultiEffectPrivate::setColorizationColor(
const QColor &color)
1101 Q_Q(QQuickMultiEffect);
1102 if (color == m_colorizationColor)
1105 m_colorizationColor = color;
1106 updateColorizationColor();
1109 Q_EMIT q->colorizationColorChanged();
1178void QQuickMultiEffectPrivate::setBlurMultiplier(qreal blurMultiplier)
1180 Q_Q(QQuickMultiEffect);
1181 if (blurMultiplier == m_blurMultiplier)
1184 m_blurMultiplier = blurMultiplier;
1185 updateSourcePadding();
1186 updateBlurItemSizes(
true);
1187 updateBlurWeights();
1188 updateShadowBlurWeights();
1191 Q_EMIT q->blurMultiplierChanged();
1237void QQuickMultiEffectPrivate::setShadowBlur(qreal shadowBlur)
1239 Q_Q(QQuickMultiEffect);
1240 if (shadowBlur == m_shadowBlur)
1243 m_shadowBlur = shadowBlur;
1244 updateShadowBlurWeights();
1247 Q_EMIT q->shadowBlurChanged();
1309void QQuickMultiEffectPrivate::setShadowScale(qreal shadowScale)
1311 Q_Q(QQuickMultiEffect);
1312 if (shadowScale == m_shadowScale)
1315 m_shadowScale = shadowScale;
1316 updateCenterOffset();
1318 m_shaderEffect->setProperty(
"shadowScale", 1.0 / m_shadowScale);
1321 Q_EMIT q->shadowScaleChanged();
1347void QQuickMultiEffectPrivate::setMaskSource(QQuickItem *item)
1349 Q_Q(QQuickMultiEffect);
1350 if (item == m_maskSourceItem)
1353 if (m_maskSourceItem) {
1354 QQuickItemPrivate::get(m_maskSourceItem)
1355 ->removeItemChangeListener(
this, ChangeType::Destroyed);
1358 QQuickItemPrivate::get(item)->addItemChangeListener(
this, ChangeType::Destroyed);
1360 m_maskSourceItem = item;
1361 if (m_shaderEffect) {
1362 auto maskSourceVariant = QVariant::fromValue<QQuickItem*>(m_maskSourceItem);
1363 m_shaderEffect->setProperty(
"maskSrc", maskSourceVariant);
1367 Q_EMIT q->maskSourceChanged();
1375void QQuickMultiEffectPrivate::setMaskThresholdMin(qreal threshold)
1377 Q_Q(QQuickMultiEffect);
1378 if (threshold == m_maskThresholdMin)
1381 m_maskThresholdMin = threshold;
1382 updateMaskThresholdSpread();
1385 Q_EMIT q->maskThresholdMinChanged();
1393void QQuickMultiEffectPrivate::setMaskSpreadAtMin(qreal spread)
1395 Q_Q(QQuickMultiEffect);
1396 if (spread == m_maskSpreadAtMin)
1399 m_maskSpreadAtMin = spread;
1400 updateMaskThresholdSpread();
1403 Q_EMIT q->maskSpreadAtMinChanged();
1411void QQuickMultiEffectPrivate::setMaskThresholdMax(qreal threshold)
1413 Q_Q(QQuickMultiEffect);
1414 if (threshold == m_maskThresholdMax)
1417 m_maskThresholdMax = threshold;
1418 updateMaskThresholdSpread();
1421 Q_EMIT q->maskThresholdMaxChanged();
1429void QQuickMultiEffectPrivate::setMaskSpreadAtMax(qreal spread)
1431 Q_Q(QQuickMultiEffect);
1432 if (spread == m_maskSpreadAtMax)
1435 m_maskSpreadAtMax = spread;
1436 updateMaskThresholdSpread();
1439 Q_EMIT q->maskSpreadAtMaxChanged();
1447void QQuickMultiEffectPrivate::setMaskInverted(
bool inverted)
1449 Q_Q(QQuickMultiEffect);
1450 if (inverted == m_maskInverted)
1453 m_maskInverted = inverted;
1455 m_shaderEffect->setProperty(
"maskInverted",
float(m_maskInverted));
1458 Q_EMIT q->maskInvertedChanged();
1461QRectF QQuickMultiEffectPrivate::itemRect()
const
1463 if (!m_shaderEffect || !m_shaderSource)
1466 QRectF sourceRect = m_shaderSource->sourceRect();
1467 if (sourceRect.width() > 0 && sourceRect.height() > 0)
1470 return m_shaderEffect->boundingRect();
1490void QQuickMultiEffectPrivate::initialize()
1492 Q_Q(QQuickMultiEffect);
1495 if (!q->isComponentComplete())
1499 if (q->width() <= 0 || q->height() <= 0)
1502 m_shaderEffect =
new QQuickShaderEffect(q);
1503 m_shaderSource =
new QGfxSourceProxyME(q);
1504 QObject::connect(m_shaderSource, &QGfxSourceProxyME::outputChanged, q, [
this] { proxyOutputChanged(); });
1505 QObject::connect(m_shaderSource, &QGfxSourceProxyME::activeChanged, q, &QQuickMultiEffect::hasProxySourceChanged);
1507 m_shaderEffect->setParentItem(q);
1508 m_shaderEffect->setSize(q->size());
1510 m_shaderSource->setParentItem(q);
1511 m_shaderSource->setSize(q->size());
1512 m_shaderSource->setInput(m_sourceItem);
1514 updateCenterOffset();
1515 updateMaskThresholdSpread();
1516 updateBlurWeights();
1517 updateShadowBlurWeights();
1518 updateColorizationColor();
1519 updateShadowColor();
1520 updateShadowOffset();
1523 auto sourceVariant = QVariant::fromValue<QQuickItem*>(m_shaderSource->output());
1524 m_shaderEffect->setProperty(
"src", sourceVariant);
1525 m_shaderEffect->setProperty(
"brightness", m_brightness);
1526 m_shaderEffect->setProperty(
"contrast", m_contrast);
1527 m_shaderEffect->setProperty(
"saturation", m_saturation);
1528 m_shaderEffect->setProperty(
"shadowScale", 1.0 / m_shadowScale);
1529 auto maskSourceVariant = QVariant::fromValue<QQuickItem*>(m_maskSourceItem);
1530 m_shaderEffect->setProperty(
"maskSrc", maskSourceVariant);
1531 m_shaderEffect->setProperty(
"maskInverted",
float(m_maskInverted));
1534 updateBlurItemSizes();
1535 updateSourcePadding();
1537 updateEffectShaders();
1539 m_initialized =
true;
1542void QQuickMultiEffectPrivate::updateMaskThresholdSpread()
1544 if (!m_shaderEffect)
1549 const qreal c0 = 0.0001;
1550 const qreal c1 = 1.0 - c0;
1551 const qreal mt1 = m_maskThresholdMin + c0;
1552 const qreal ms1 = m_maskSpreadAtMin + 1.0;
1553 const qreal mt2 = c1 - m_maskThresholdMax;
1554 const qreal ms2 = m_maskSpreadAtMax + 1.0;
1555 const QVector4D maskThresholdSpread = QVector4D(
1556 mt1 * ms1 - (ms1 - c1),
1558 mt2 * ms2 - (ms2 - c1),
1560 m_shaderEffect->setProperty(
"mask", maskThresholdSpread);
1563void QQuickMultiEffectPrivate::updateCenterOffset()
1565 if (!m_shaderEffect)
1568 const qreal scale = 1.0 / m_shadowScale;
1569 QVector2D centerOffset((1.0 - scale) * (0.5 + 0.5 * (m_paddingRect.x() - m_paddingRect.width()) / m_shaderEffect->width()),
1570 (1.0 - scale) * (0.5 + 0.5 * (m_paddingRect.y() - m_paddingRect.height()) / m_shaderEffect->height()));
1571 m_shaderEffect->setProperty(
"centerOffset", centerOffset);
1583void QQuickMultiEffectPrivate::updateColorizationColor()
1585 if (!m_shaderEffect)
1588 float alpha = std::clamp(
float(m_colorizationColor.alphaF() * m_colorization), 0.0f, 1.0f);
1589 QVector4D colorizationColor(m_colorizationColor.redF(),
1590 m_colorizationColor.greenF(),
1591 m_colorizationColor.blueF(),
1593 m_shaderEffect->setProperty(
"colorizationColor", colorizationColor);
1596void QQuickMultiEffectPrivate::updateShadowColor()
1598 if (!m_shaderEffect)
1602 float alpha = std::clamp(
float(m_shadowOpacity), 0.0f, 1.0f);
1603 QVector4D shadowColor(m_shadowColor.redF() * alpha,
1604 m_shadowColor.greenF() * alpha,
1605 m_shadowColor.blueF() * alpha,
1606 m_shadowColor.alphaF() * alpha);
1607 m_shaderEffect->setProperty(
"shadowColor", shadowColor);
1620void QQuickMultiEffectPrivate::getBlurWeights(
float blurLod, QVector4D &blurWeight1, QVector2D &blurWeight2)
1622 float bw1 = blurWeight(std::fabs(blurLod - 0.1f));
1623 float bw2 = blurWeight(std::fabs(blurLod - 0.3f));
1624 float bw3 = blurWeight(std::fabs(blurLod - 0.5f));
1625 float bw4 = blurWeight(std::fabs(blurLod - 0.7f));
1626 float bw5 = blurWeight(std::fabs(blurLod - 0.9f));
1627 float bw6 = blurWeight(std::fabs(blurLod - 1.1f));
1628 float bsum = bw1 + bw2 + bw3 + bw4 + bw5 + bw6;
1629 blurWeight1 = QVector4D(bw1 / bsum, bw2 / bsum, bw3 / bsum, bw4 / bsum);
1630 blurWeight2 = QVector2D(bw5 / bsum, bw6 / bsum);
1633void QQuickMultiEffectPrivate::updateBlurWeights()
1635 if (!m_shaderEffect)
1637 float blurLod = calculateLod(m_blur);
1638 getBlurWeights(blurLod, m_blurWeight1, m_blurWeight2);
1639 m_shaderEffect->setProperty(
"blurWeight1", m_blurWeight1);
1640 m_shaderEffect->setProperty(
"blurWeight2", m_blurWeight2);
1643void QQuickMultiEffectPrivate::updateShadowBlurWeights()
1645 if (!m_shaderEffect)
1647 float blurLod = calculateLod(m_shadowBlur);
1648 getBlurWeights(blurLod, m_shadowBlurWeight1, m_shadowBlurWeight2);
1649 m_shaderEffect->setProperty(
"shadowBlurWeight1", m_shadowBlurWeight1);
1650 m_shaderEffect->setProperty(
"shadowBlurWeight2", m_shadowBlurWeight2);
1653void QQuickMultiEffectPrivate::updateBlurItemSizes(
bool forceUpdate)
1655 if (m_blurEffects.isEmpty() || !m_shaderSource || !m_sourceItem)
1660 QSizeF sourceSize = itemRect().size();
1661 QSizeF firstItemSize(std::ceil(sourceSize.width() / 16) * 8,
1662 std::ceil(sourceSize.height() / 16) * 8);
1664 if (!forceUpdate && m_firstBlurItemSize == firstItemSize)
1667 qCDebug(lcQuickEffect) <<
"Source size:" << sourceSize;
1668 m_firstBlurItemSize = firstItemSize;
1670 for (
int i = 0; i < m_blurEffects.size(); i++) {
1671 auto *blurEffect = m_blurEffects[i];
1672 QSizeF itemSize = (i == 0) ? firstItemSize : m_blurEffects[i - 1]->size() * 0.5;
1673 qCDebug(lcQuickEffect) <<
"Blur item" << i <<
":" << itemSize;
1674 blurEffect->setSize(itemSize);
1676 const QVector2D offset((1.0 + m_blurMultiplier) / itemSize.width(),
1677 (1.0 + m_blurMultiplier) / itemSize.height());
1678 blurEffect->setProperty(
"offset", offset);
1682void QQuickMultiEffectPrivate::updateEffectShaders()
1684 Q_Q(QQuickMultiEffect);
1685 if (!q->isComponentComplete() || !m_shaderEffect)
1688 QString vShader = QStringLiteral(
"multieffect_c");
1689 if (m_shadowEnabled)
1690 vShader += QStringLiteral(
"s");
1692 QString fShader = QStringLiteral(
"multieffect_c");
1694 fShader += QStringLiteral(
"m");
1695 if (m_blurEnabled && m_blurMax > 0)
1696 fShader += QStringLiteral(
"b");
1697 if (m_shadowEnabled)
1698 fShader += QStringLiteral(
"s");
1700 fShader += QString::number(m_blurLevel);
1702 bool shaderChanged =
false;
1703 if (fShader != m_fragShader) {
1704 shaderChanged =
true;
1705 m_fragShader = fShader;
1706 QUrl fs = QUrl(QStringLiteral(
"qrc:/data/shaders/%1.frag.qsb").arg(m_fragShader));
1707 m_shaderEffect->setFragmentShader(fs);
1708 Q_EMIT q->fragmentShaderChanged();
1710 if (vShader != m_vertShader) {
1711 shaderChanged =
true;
1712 m_vertShader = vShader;
1713 QUrl vs = QUrl(QStringLiteral(
"qrc:/data/shaders/%1.vert.qsb").arg(m_vertShader));
1714 m_shaderEffect->setVertexShader(vs);
1715 Q_EMIT q->vertexShaderChanged();
1717 if (shaderChanged) {
1718 qCDebug(lcQuickEffect) <<
this <<
"Shaders: " << m_fragShader << m_vertShader;
1719 Q_EMIT q->shaderChanged();
1723void QQuickMultiEffectPrivate::updateBlurLevel(
bool forceUpdate)
1726 if ((m_blurEnabled || m_shadowEnabled) && m_blurMax > 0) {
1729 else if (m_blurMax > 16)
1735 if (blurLevel != m_blurLevel || (blurLevel > 0 && m_blurEffects.isEmpty()) || forceUpdate) {
1738 updateBlurItemsAmount(blurLevel);
1740 if (blurLevel > m_blurLevel)
1741 updateBlurItemSizes(
true);
1743 m_blurLevel = blurLevel;
1746void QQuickMultiEffectPrivate::updateBlurItemsAmount(
int blurLevel)
1748 Q_Q(QQuickMultiEffect);
1749 if (!m_shaderEffect)
1752 const auto engine = qmlEngine(q);
1757 int itemsAmount = blurLevel == 0 ? 0 : blurLevel + 2;
1759 if (m_blurEffects.size() < itemsAmount) {
1763 QUrl blurVs = QUrl(QStringLiteral(
"qrc:/data/shaders/bluritems.vert.qsb"));
1764 QUrl blurFs = QUrl(QStringLiteral(
"qrc:/data/shaders/bluritems.frag.qsb"));
1765 QQmlComponent blurComponent(
1767 QUrl(QStringLiteral(
"qrc:/qt-project.org/imports/QtQuick/Effects/BlurItem.qml")));
1768 for (
int i = m_blurEffects.size(); i < itemsAmount; i++) {
1769 auto blurEffect = qobject_cast<QQuickShaderEffect*>(blurComponent.create());
1770 blurEffect->setParent(q);
1771 blurEffect->setParentItem(q);
1772 auto sourceVariant = QVariant::fromValue<QQuickItem*>(blurEffect);
1773 QString sourceProperty = QStringLiteral(
"blurSrc%1").arg(i + 1);
1774 m_shaderEffect->setProperty(sourceProperty.toUtf8(), sourceVariant);
1777 blurEffect->setProperty(
"source", sourceVariant);
1778 QQuickItemPrivate *priv = QQuickItemPrivate::get(blurEffect);
1779 priv->layer()->setEnabled(
true);
1780 priv->layer()->setSmooth(
true);
1781 blurEffect->setVertexShader(blurVs);
1782 blurEffect->setFragmentShader(blurFs);
1783 m_blurEffects << blurEffect;
1788 if (!m_dummyShaderSource)
1789 m_dummyShaderSource =
new QQuickShaderEffectSource(q);
1790 for (
int i = 0; i < m_blurEffects.size(); i++) {
1791 auto *blurEffect = m_blurEffects[i];
1792 auto sourceItem = (i >= itemsAmount) ?
1793 static_cast<QQuickItem *>(m_dummyShaderSource) : (i == 0) ?
1794 static_cast<QQuickItem *>(m_shaderSource->output()) :
1795 static_cast<QQuickItem *>(m_blurEffects[i - 1]);
1796 auto sourceVariant = QVariant::fromValue<QQuickItem*>(sourceItem);
1797 blurEffect->setProperty(
"source", sourceVariant);
1801void QQuickMultiEffectPrivate::updateSourcePadding()
1803 Q_Q(QQuickMultiEffect);
1804 if (!m_shaderEffect || !m_shaderSource)
1807 const bool blurItemsNeeded = (m_blurEnabled || m_shadowEnabled) && (m_blurMax > 0);
1808 const int itemPadding = m_autoPaddingEnabled && blurItemsNeeded ? m_blurMax * (1.0 + m_blurMultiplier) : 0;
1811 if (m_paddingRect != QRectF() || itemPadding > 0) {
1812 QRectF effectRect(-m_paddingRect.x() - itemPadding,
1813 -m_paddingRect.y() - itemPadding,
1814 q->width() + m_paddingRect.x() + m_paddingRect.width() + (itemPadding * 2),
1815 q->height() + m_paddingRect.y() + m_paddingRect.height() + (itemPadding * 2));
1816 m_shaderEffect->setX(effectRect.x());
1817 m_shaderEffect->setY(effectRect.y());
1818 m_shaderEffect->setWidth(effectRect.width());
1819 m_shaderEffect->setHeight(effectRect.height());
1822 m_shaderSource->setSize(m_shaderEffect->size());
1827 const qreal baseWidth = m_sourceItem && m_sourceItem->width() > 0 ? m_sourceItem->width() : q->width();
1828 const qreal baseHeight = m_sourceItem && m_sourceItem->height() > 0 ? m_sourceItem->height() : q->height();
1831 const qreal widthMultiplier = q->width() > 0 ? baseWidth / q->width() : 1.0;
1832 const qreal heightMultiplier = q->height() > 0 ? baseHeight / q->height() : 1.0;
1833 const qreal xPadding = itemPadding * widthMultiplier;
1834 const qreal yPadding = itemPadding * heightMultiplier;
1835 QRectF rect = QRectF(m_paddingRect.x() * widthMultiplier,
1836 m_paddingRect.y() * heightMultiplier,
1837 m_paddingRect.width() * widthMultiplier,
1838 m_paddingRect.height() * heightMultiplier);
1839 QRectF sourceRect = QRectF(-rect.x() - xPadding,
1840 -rect.y() - yPadding,
1841 baseWidth + rect.x() + rect.width() + xPadding * 2,
1842 baseHeight + rect.y() + rect.height() + yPadding * 2);
1843 m_shaderSource->setSourceRect(sourceRect);
1845 m_shaderEffect->setX(0);
1846 m_shaderEffect->setY(0);
1847 m_shaderEffect->setSize(q->size());
1848 m_shaderSource->setSize(q->size());
1849 m_shaderSource->setSourceRect(QRectF());
1852 updateShadowOffset();
1853 updateProxyActiveCheck();
1854 updateBlurItemSizes();
1855 Q_EMIT q->paddingRectChanged();
1856 Q_EMIT q->itemRectChanged();
1857 Q_EMIT q->itemSizeChanged();