Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickmultieffect.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qtypes.h"
5#include <private/qquickmultieffect_p_p.h>
6#include <private/qquickshadereffect_p.h>
7#include <private/qquickshadereffectsource_p.h>
8
10
11Q_LOGGING_CATEGORY(lcQuickEffect, "qt.quick.effects")
12
13
161{
162 setFlag(ItemHasContents);
163}
164
168
187{
188 Q_D(const QQuickMultiEffect);
189 return d->source();
190}
191
193{
195 d->setSource(item);
196}
197
214{
215 Q_D(const QQuickMultiEffect);
216 return d->autoPaddingEnabled();
217}
218
220{
222 d->setAutoPaddingEnabled(enabled);
223}
224
246{
247 Q_D(const QQuickMultiEffect);
248 return d->paddingRect();
249}
250
252{
254 d->setPaddingRect(rect);
255}
256
267{
268 Q_D(const QQuickMultiEffect);
269 return d->brightness();
270}
271
273{
275 d->setBrightness(brightness);
276}
277
288{
289 Q_D(const QQuickMultiEffect);
290 return d->contrast();
291}
292
294{
296 d->setContrast(contrast);
297}
298
309{
310 Q_D(const QQuickMultiEffect);
311 return d->saturation();
312}
313
315{
317 d->setSaturation(saturation);
318}
319
330{
331 Q_D(const QQuickMultiEffect);
332 return d->colorization();
333}
334
336{
338 d->setColorization(colorization);
339}
340
352{
353 Q_D(const QQuickMultiEffect);
354 return d->colorizationColor();
355}
356
358{
360 d->setColorizationColor(color);
361}
362
371{
372 Q_D(const QQuickMultiEffect);
373 return d->blurEnabled();
374}
375
377{
379 d->setBlurEnabled(enabled);
380}
381
396{
397 Q_D(const QQuickMultiEffect);
398 return d->blur();
399}
400
402{
404 d->setBlur(blur);
405}
406
424{
425 Q_D(const QQuickMultiEffect);
426 return d->blurMax();
427}
428
430{
432 d->setBlurMax(blurMax);
433}
434
451{
452 Q_D(const QQuickMultiEffect);
453 return d->blurMultiplier();
454}
455
457{
459 d->setBlurMultiplier(blurMultiplier);
460}
461
470{
471 Q_D(const QQuickMultiEffect);
472 return d->shadowEnabled();
473}
474
476{
478 d->setShadowEnabled(enabled);
479}
480
491{
492 Q_D(const QQuickMultiEffect);
493 return d->shadowOpacity();
494}
495
497{
499 d->setShadowOpacity(shadowOpacity);
500}
501
516{
517 Q_D(const QQuickMultiEffect);
518 return d->shadowBlur();
519}
520
522{
524 d->setShadowBlur(shadowBlur);
525}
526
541{
542 Q_D(const QQuickMultiEffect);
543 return d->shadowHorizontalOffset();
544}
545
547{
549 d->setShadowHorizontalOffset(offset);
550}
551
566{
567 Q_D(const QQuickMultiEffect);
568 return d->shadowVerticalOffset();
569}
570
572{
574 d->setShadowVerticalOffset(offset);
575}
576
588{
589 Q_D(const QQuickMultiEffect);
590 return d->shadowColor();
591}
592
594{
596 d->setShadowColor(color);
597}
598
613{
614 Q_D(const QQuickMultiEffect);
615 return d->shadowScale();
616}
617
619{
621 d->setShadowScale(shadowScale);
622}
623
632{
633 Q_D(const QQuickMultiEffect);
634 return d->maskEnabled();
635}
636
638{
640 d->setMaskEnabled(enabled);
641}
642
652{
653 Q_D(const QQuickMultiEffect);
654 return d->maskSource();
655}
656
658{
660 d->setMaskSource(item);
661}
662
676{
677 Q_D(const QQuickMultiEffect);
678 return d->maskThresholdMin();
679}
680
682{
684 d->setMaskThresholdMin(threshold);
685}
686
699{
700 Q_D(const QQuickMultiEffect);
701 return d->maskSpreadAtMin();
702}
703
705{
707 d->setMaskSpreadAtMin(spread);
708}
709
723{
724 Q_D(const QQuickMultiEffect);
725 return d->maskThresholdMax();
726}
727
729{
731 d->setMaskThresholdMax(threshold);
732}
733
746{
747 Q_D(const QQuickMultiEffect);
748 return d->maskSpreadAtMax();
749}
750
752{
754 d->setMaskSpreadAtMax(spread);
755}
756
767{
768 Q_D(const QQuickMultiEffect);
769 return d->maskInverted();
770}
771
773{
775 d->setMaskInverted(inverted);
776}
777
788{
789 Q_D(const QQuickMultiEffect);
790 return d->itemRect();
791}
792
800{
801 Q_D(const QQuickMultiEffect);
802 return d->fragmentShader();
803}
804
812{
813 Q_D(const QQuickMultiEffect);
814 return d->vertexShader();
815}
816
828{
829 Q_D(const QQuickMultiEffect);
830 return d->hasProxySource();
831}
832
833// *** protected ***
834
841
842void QQuickMultiEffect::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
843{
845 QQuickItem::geometryChange(newGeometry, oldGeometry);
846 if (width() > 0 && height() > 0)
847 d->handleGeometryChange(newGeometry, oldGeometry);
848}
849
851{
853 d->handleItemChange(change, value);
855}
856
857// *** private ***
858
862
866
867void QQuickMultiEffectPrivate::handleGeometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
868{
869 Q_UNUSED(oldGeometry);
870 Q_UNUSED(newGeometry);
871 initialize();
872 if (!m_shaderEffect)
873 return;
876}
877
884
885
887{
888 return m_sourceItem;
889}
890
892{
894 if (item == m_sourceItem)
895 return;
896
897 m_sourceItem = item;
898 if (m_shaderSource)
899 m_shaderSource->setInput(m_sourceItem);
900
902 q->update();
903 Q_EMIT q->sourceChanged();
904}
905
907{
908 return m_autoPaddingEnabled;
909}
910
912{
914 if (enabled == m_autoPaddingEnabled)
915 return;
916
917 m_autoPaddingEnabled = enabled;
919 q->update();
920 Q_EMIT q->autoPaddingEnabledChanged();
921}
922
924{
925 return m_paddingRect;
926}
927
929{
931 if (rect == m_paddingRect)
932 return;
933 m_paddingRect = rect;
936 q->update();
937 emit q->paddingRectChanged();
938}
939
941{
942 return m_brightness;
943}
944
946{
948 if (brightness == m_brightness)
949 return;
950
951 m_brightness = brightness;
952 if (m_shaderEffect)
953 m_shaderEffect->setProperty("brightness", m_brightness);
954
955 q->update();
956 Q_EMIT q->brightnessChanged();
957}
958
960{
961 return m_contrast;
962}
963
965{
967 if (contrast == m_contrast)
968 return;
969
970 m_contrast = contrast;
971 if (m_shaderEffect)
972 m_shaderEffect->setProperty("contrast", m_contrast);
973
974 q->update();
975 Q_EMIT q->contrastChanged();
976}
977
979{
980 return m_saturation;
981}
982
984{
986 if (saturation == m_saturation)
987 return;
988
989 m_saturation = saturation;
990 if (m_shaderEffect)
991 m_shaderEffect->setProperty("saturation", m_saturation);
992
993 q->update();
994 Q_EMIT q->saturationChanged();
995}
996
998{
999 return m_colorization;
1000}
1001
1003{
1004 Q_Q(QQuickMultiEffect);
1005 if (colorization == m_colorization)
1006 return;
1007
1008 m_colorization = colorization;
1010
1011 q->update();
1012 Q_EMIT q->colorizationChanged();
1013}
1014
1016{
1017 return m_colorizationColor;
1018}
1019
1021{
1022 Q_Q(QQuickMultiEffect);
1023 if (color == m_colorizationColor)
1024 return;
1025
1026 m_colorizationColor = color;
1028
1029 q->update();
1030 Q_EMIT q->colorizationColorChanged();
1031}
1032
1034{
1035 return m_blurEnabled;
1036}
1037
1039{
1040 Q_Q(QQuickMultiEffect);
1041 if (enabled == m_blurEnabled)
1042 return;
1043
1044 m_blurEnabled = enabled;
1048
1049 q->update();
1050 Q_EMIT q->blurEnabledChanged();
1051}
1052
1054{
1055 return m_blur;
1056}
1057
1059{
1060 Q_Q(QQuickMultiEffect);
1061 if (blur == m_blur)
1062 return;
1063
1064 m_blur = blur;
1066
1067 q->update();
1068 Q_EMIT q->blurChanged();
1069}
1070
1072{
1073 return m_blurMax;
1074}
1075
1077{
1078 Q_Q(QQuickMultiEffect);
1079 if (blurMax == m_blurMax)
1080 return;
1081
1082 m_blurMax = blurMax;
1089
1090 q->update();
1091 Q_EMIT q->blurMaxChanged();
1092}
1093
1095{
1096 return m_blurMultiplier;
1097}
1098
1100{
1101 Q_Q(QQuickMultiEffect);
1102 if (blurMultiplier == m_blurMultiplier)
1103 return;
1104
1105 m_blurMultiplier = blurMultiplier;
1107 updateBlurItemSizes(true);
1110
1111 q->update();
1112 Q_EMIT q->blurMultiplierChanged();
1113}
1114
1116{
1117 return m_shadowEnabled;
1118}
1119
1121{
1122 Q_Q(QQuickMultiEffect);
1123 if (enabled == m_shadowEnabled)
1124 return;
1125
1126 m_shadowEnabled = enabled;
1130
1131 q->update();
1132 Q_EMIT q->shadowEnabledChanged();
1133}
1134
1136{
1137 return m_shadowOpacity;
1138}
1139
1141{
1142 Q_Q(QQuickMultiEffect);
1143 if (shadowOpacity == m_shadowOpacity)
1144 return;
1145
1146 m_shadowOpacity = shadowOpacity;
1148
1149 q->update();
1150 Q_EMIT q->shadowOpacityChanged();
1151}
1152
1154{
1155 return m_shadowBlur;
1156}
1157
1159{
1160 Q_Q(QQuickMultiEffect);
1161 if (shadowBlur == m_shadowBlur)
1162 return;
1163
1164 m_shadowBlur = shadowBlur;
1166
1167 q->update();
1168 Q_EMIT q->shadowBlurChanged();
1169}
1170
1172{
1173 return m_shadowHorizontalOffset;
1174}
1175
1177{
1178 Q_Q(QQuickMultiEffect);
1179 if (offset == m_shadowHorizontalOffset)
1180 return;
1181
1182 m_shadowHorizontalOffset = offset;
1184
1185 q->update();
1186 Q_EMIT q->shadowHorizontalOffsetChanged();
1187}
1188
1190{
1191 return m_shadowVerticalOffset;
1192}
1193
1195{
1196 Q_Q(QQuickMultiEffect);
1197 if (offset == m_shadowVerticalOffset)
1198 return;
1199
1200 m_shadowVerticalOffset = offset;
1202
1203 q->update();
1204 Q_EMIT q->shadowVerticalOffsetChanged();
1205}
1206
1208{
1209 return m_shadowColor;
1210}
1211
1213{
1214 Q_Q(QQuickMultiEffect);
1215 if (color == m_shadowColor)
1216 return;
1217
1218 m_shadowColor = color;
1220
1221 q->update();
1222 Q_EMIT q->shadowColorChanged();
1223}
1224
1226{
1227 return m_shadowScale;
1228}
1229
1231{
1232 Q_Q(QQuickMultiEffect);
1233 if (shadowScale == m_shadowScale)
1234 return;
1235
1236 m_shadowScale = shadowScale;
1238 if (m_shaderEffect)
1239 m_shaderEffect->setProperty("shadowScale", 1.0 / m_shadowScale);
1240
1241 q->update();
1242 Q_EMIT q->shadowScaleChanged();
1243}
1244
1246{
1247 return m_maskEnabled;
1248}
1249
1251{
1252 Q_Q(QQuickMultiEffect);
1253 if (enabled == m_maskEnabled)
1254 return;
1255
1256 m_maskEnabled = enabled;
1258
1259 q->update();
1260 Q_EMIT q->maskEnabledChanged();
1261}
1262
1264{
1265 return m_maskSourceItem;
1266}
1267
1269{
1270 Q_Q(QQuickMultiEffect);
1271 if (item == m_maskSourceItem)
1272 return;
1273
1274 m_maskSourceItem = item;
1275 if (m_shaderEffect) {
1276 auto maskSourceVariant = QVariant::fromValue<QQuickItem*>(m_maskSourceItem);
1277 m_shaderEffect->setProperty("maskSrc", maskSourceVariant);
1278 }
1279
1280 q->update();
1281 Q_EMIT q->maskSourceChanged();
1282}
1283
1285{
1286 return m_maskThresholdMin;
1287}
1288
1290{
1291 Q_Q(QQuickMultiEffect);
1292 if (threshold == m_maskThresholdMin)
1293 return;
1294
1295 m_maskThresholdMin = threshold;
1297
1298 q->update();
1299 Q_EMIT q->maskThresholdMinChanged();
1300}
1301
1303{
1304 return m_maskSpreadAtMin;
1305}
1306
1308{
1309 Q_Q(QQuickMultiEffect);
1310 if (spread == m_maskSpreadAtMin)
1311 return;
1312
1313 m_maskSpreadAtMin = spread;
1315
1316 q->update();
1317 Q_EMIT q->maskSpreadAtMinChanged();
1318}
1319
1321{
1322 return m_maskThresholdMax;
1323}
1324
1326{
1327 Q_Q(QQuickMultiEffect);
1328 if (threshold == m_maskThresholdMax)
1329 return;
1330
1331 m_maskThresholdMax = threshold;
1333
1334 q->update();
1335 Q_EMIT q->maskThresholdMaxChanged();
1336}
1337
1339{
1340 return m_maskSpreadAtMax;
1341}
1342
1344{
1345 Q_Q(QQuickMultiEffect);
1346 if (spread == m_maskSpreadAtMax)
1347 return;
1348
1349 m_maskSpreadAtMax = spread;
1351
1352 q->update();
1353 Q_EMIT q->maskSpreadAtMaxChanged();
1354}
1355
1357{
1358 return m_maskInverted;
1359}
1360
1362{
1363 Q_Q(QQuickMultiEffect);
1364 if (inverted == m_maskInverted)
1365 return;
1366
1367 m_maskInverted = inverted;
1368 if (m_shaderEffect)
1369 m_shaderEffect->setProperty("maskInverted", float(m_maskInverted));
1370
1371 q->update();
1372 Q_EMIT q->maskInvertedChanged();
1373}
1374
1376{
1377 if (!m_shaderEffect || !m_shaderSource)
1378 return QRectF();
1379
1380 QRectF sourceRect = m_shaderSource->sourceRect();
1381 if (sourceRect.width() > 0 && sourceRect.height() > 0)
1382 return sourceRect;
1383 else
1384 return m_shaderEffect->boundingRect();
1385}
1386
1388{
1389 return m_fragShader;
1390}
1391
1393{
1394 return m_vertShader;
1395}
1396
1398{
1399 return m_shaderSource && m_shaderSource->isActive();
1400}
1401
1402// This initializes the component. It will be ran once, when
1403// the component is ready and it has a valid size.
1405{
1406 Q_Q(QQuickMultiEffect);
1407 if (m_initialized)
1408 return;
1409 if (!q->isComponentComplete())
1410 return;
1411 if (!q->window())
1412 return;
1413 if (q->width() <= 0 || q->height() <= 0)
1414 return;
1415
1416 m_shaderEffect = new QQuickShaderEffect(q);
1417 m_shaderSource = new QGfxSourceProxy(q);
1418 QObject::connect(m_shaderSource, &QGfxSourceProxy::outputChanged, q, [this] { proxyOutputChanged(); });
1420
1421 m_shaderEffect->setParentItem(q);
1422 m_shaderEffect->setSize(q->size());
1423
1424 m_shaderSource->setParentItem(q);
1425 m_shaderSource->setSize(q->size());
1426 m_shaderSource->setInput(m_sourceItem);
1427
1435
1436 // Create properties
1437 auto sourceVariant = QVariant::fromValue<QQuickItem*>(m_shaderSource->output());
1438 m_shaderEffect->setProperty("src", sourceVariant);
1439 m_shaderEffect->setProperty("brightness", m_brightness);
1440 m_shaderEffect->setProperty("contrast", m_contrast);
1441 m_shaderEffect->setProperty("saturation", m_saturation);
1442 m_shaderEffect->setProperty("shadowScale", 1.0 / m_shadowScale);
1443 auto maskSourceVariant = QVariant::fromValue<QQuickItem*>(m_maskSourceItem);
1444 m_shaderEffect->setProperty("maskSrc", maskSourceVariant);
1445 m_shaderEffect->setProperty("maskInverted", float(m_maskInverted));
1446
1450
1452
1453 m_initialized = true;
1454}
1455
1457{
1458 if (!m_shaderEffect)
1459 return;
1460
1461 // Calculate threshold and spread values for mask
1462 // smoothstep, keeping always edge0 < edge1.
1463 const qreal c0 = 0.0001;
1464 const qreal c1 = 1.0 - c0;
1465 const qreal mt1 = m_maskThresholdMin + c0;
1466 const qreal ms1 = m_maskSpreadAtMin + 1.0;
1467 const qreal mt2 = c1 - m_maskThresholdMax;
1468 const qreal ms2 = m_maskSpreadAtMax + 1.0;
1469 const QVector4D maskThresholdSpread = QVector4D(
1470 mt1 * ms1 - (ms1 - c1),
1471 mt1 * ms1,
1472 mt2 * ms2 - (ms2 - c1),
1473 mt2 * ms2);
1474 m_shaderEffect->setProperty("mask", maskThresholdSpread);
1475}
1476
1478{
1479 if (!m_shaderEffect)
1480 return;
1481
1482 const qreal scale = 1.0 / m_shadowScale;
1483 QVector2D centerOffset((1.0 - scale) * (0.5 + 0.5 * (m_paddingRect.x() - m_paddingRect.width()) / m_shaderEffect->width()),
1484 (1.0 - scale) * (0.5 + 0.5 * (m_paddingRect.y() - m_paddingRect.height()) / m_shaderEffect->height()));
1485 m_shaderEffect->setProperty("centerOffset", centerOffset);
1486}
1487
1489{
1490 if (!m_shaderEffect)
1491 return;
1492
1493 QVector2D shadowOffset = QVector2D(m_shadowHorizontalOffset / m_shaderEffect->width(), m_shadowVerticalOffset / m_shaderEffect->height());
1494 m_shaderEffect->setProperty("shadowOffset", shadowOffset);
1495}
1496
1498{
1499 if (!m_shaderEffect)
1500 return;
1501
1502 float alpha = std::clamp(float(m_colorizationColor.alphaF() * m_colorization), 0.0f, 1.0f);
1503 QVector4D colorizationColor(m_colorizationColor.redF(),
1504 m_colorizationColor.greenF(),
1505 m_colorizationColor.blueF(),
1506 alpha);
1507 m_shaderEffect->setProperty("colorizationColor", colorizationColor);
1508}
1509
1511{
1512 if (!m_shaderEffect)
1513 return;
1514
1515 float alpha = std::clamp(float(m_shadowColor.alphaF() * m_shadowOpacity), 0.0f, 1.0f);
1516 QVector4D shadowColor(m_shadowColor.redF(),
1517 m_shadowColor.greenF(),
1518 m_shadowColor.blueF(),
1519 alpha);
1520
1521 m_shaderEffect->setProperty("shadowColor", shadowColor);
1522}
1523
1525{
1526 return qSqrt(blurAmount * float(m_blurMax) / 64.0f) * 1.2f - 0.2f;
1527}
1528
1530{
1531 return std::max(0.0f, std::min(1.0f, 1.0f - v * 2.0f));
1532}
1533
1534void QQuickMultiEffectPrivate::getBlurWeights(float blurLod, QVector4D &blurWeight1, QVector2D &blurWeight2)
1535{
1536 float bw1 = blurWeight(std::fabs(blurLod - 0.1f));
1537 float bw2 = blurWeight(std::fabs(blurLod - 0.3f));
1538 float bw3 = blurWeight(std::fabs(blurLod - 0.5f));
1539 float bw4 = blurWeight(std::fabs(blurLod - 0.7f));
1540 float bw5 = blurWeight(std::fabs(blurLod - 0.9f));
1541 float bw6 = blurWeight(std::fabs(blurLod - 1.1f));
1542 float bsum = bw1 + bw2 + bw3 + bw4 + bw5 + bw6;
1543 blurWeight1 = QVector4D(bw1 / bsum, bw2 / bsum, bw3 / bsum, bw4 / bsum);
1544 blurWeight2 = QVector2D(bw5 / bsum, bw6 / bsum);
1545}
1546
1548{
1549 if (!m_shaderEffect)
1550 return;
1551 float blurLod = calculateLod(m_blur);
1552 getBlurWeights(blurLod, m_blurWeight1, m_blurWeight2);
1553 m_shaderEffect->setProperty("blurWeight1", m_blurWeight1);
1554 m_shaderEffect->setProperty("blurWeight2", m_blurWeight2);
1555}
1556
1558{
1559 if (!m_shaderEffect)
1560 return;
1561 float blurLod = calculateLod(m_shadowBlur);
1562 getBlurWeights(blurLod, m_shadowBlurWeight1, m_shadowBlurWeight2);
1563 m_shaderEffect->setProperty("shadowBlurWeight1", m_shadowBlurWeight1);
1564 m_shaderEffect->setProperty("shadowBlurWeight2", m_shadowBlurWeight2);
1565}
1566
1568{
1569 if (m_blurEffects.isEmpty() || !m_shaderSource || !m_sourceItem)
1570 return;
1571
1572 // First blur item size to be half of th source item
1573 // extended size, rounded to next divisible by 16.
1574 QSizeF sourceSize = itemRect().size();
1575 QSizeF firstItemSize(std::ceil(sourceSize.width() / 16) * 8,
1576 std::ceil(sourceSize.height() / 16) * 8);
1577
1578 if (!forceUpdate && m_firstBlurItemSize == firstItemSize)
1579 return;
1580
1581 qCDebug(lcQuickEffect) << "Source size:" << sourceSize;
1582 m_firstBlurItemSize = firstItemSize;
1583
1584 for (int i = 0; i < m_blurEffects.size(); i++) {
1585 auto *blurEffect = m_blurEffects[i];
1586 QSizeF itemSize = (i == 0) ? firstItemSize : m_blurEffects[i - 1]->size() * 0.5;
1587 qCDebug(lcQuickEffect) << "Blur item" << i << ":" << itemSize;
1588 blurEffect->setSize(itemSize);
1589
1590 const QVector2D offset((1.0 + m_blurMultiplier) / itemSize.width(),
1591 (1.0 + m_blurMultiplier) / itemSize.height());
1592 blurEffect->setProperty("offset", offset);
1593 }
1594}
1595
1597{
1598 Q_Q(QQuickMultiEffect);
1599 if (!q->isComponentComplete() || !m_shaderEffect)
1600 return;
1601
1602 QString vShader = QStringLiteral("multieffect_c");
1603 if (m_shadowEnabled)
1604 vShader += QStringLiteral("s");
1605
1606 QString fShader = QStringLiteral("multieffect_c");
1607 if (m_maskEnabled)
1608 fShader += QStringLiteral("m");
1609 if (m_blurEnabled && m_blurMax > 0)
1610 fShader += QStringLiteral("b");
1611 if (m_shadowEnabled)
1612 fShader += QStringLiteral("s");
1613
1614 fShader += QString::number(m_blurLevel);
1615
1616 bool shaderChanged = false;
1617 if (fShader != m_fragShader) {
1618 shaderChanged = true;
1619 m_fragShader = fShader;
1620 QUrl fs = QUrl(QStringLiteral("qrc:/data/shaders/%1.frag.qsb").arg(m_fragShader));
1621 m_shaderEffect->setFragmentShader(fs);
1622 Q_EMIT q->fragmentShaderChanged();
1623 }
1624 if (vShader != m_vertShader) {
1625 shaderChanged = true;
1626 m_vertShader = vShader;
1627 QUrl vs = QUrl(QStringLiteral("qrc:/data/shaders/%1.vert.qsb").arg(m_vertShader));
1628 m_shaderEffect->setVertexShader(vs);
1629 Q_EMIT q->vertexShaderChanged();
1630 }
1631 if (shaderChanged) {
1632 qCDebug(lcQuickEffect) << this << "Shaders: " << m_fragShader << m_vertShader;
1633 Q_EMIT q->shaderChanged();
1634 }
1635}
1636
1638{
1639 int blurLevel = 0;
1640 if ((m_blurEnabled || m_shadowEnabled) && m_blurMax > 0) {
1641 if (m_blurMax > 32)
1642 blurLevel = 3;
1643 else if (m_blurMax > 16)
1644 blurLevel = 2;
1645 else
1646 blurLevel = 1;
1647 }
1648
1649 if (blurLevel != m_blurLevel || (blurLevel > 0 && m_blurEffects.isEmpty()) || forceUpdate) {
1650 // Blur level has changed or blur items need to be
1651 // initially created.
1652 updateBlurItemsAmount(blurLevel);
1653 // When the level grows, new items must be resized
1654 if (blurLevel > m_blurLevel)
1655 updateBlurItemSizes(true);
1656 }
1657 m_blurLevel = blurLevel;
1658}
1659
1661{
1662 Q_Q(QQuickMultiEffect);
1663 if (!m_shaderEffect)
1664 return;
1665
1666 const auto engine = qmlEngine(q);
1667 if (!engine)
1668 return;
1669
1670 // Lowest blur level uses 3 items, highest 5 items.
1671 int itemsAmount = blurLevel == 0 ? 0 : blurLevel + 2;
1672
1673 if (m_blurEffects.size() < itemsAmount) {
1674 // Add more blur items.
1675 // Note that by design blur items are only added and never reduced
1676 // during the lifetime of the effect component.
1677 QUrl blurVs = QUrl(QStringLiteral("qrc:/data/shaders/bluritems.vert.qsb"));
1678 QUrl blurFs = QUrl(QStringLiteral("qrc:/data/shaders/bluritems.frag.qsb"));
1679 QQmlComponent blurComponent(engine, QUrl(QStringLiteral("qrc:/data/BlurItem.qml")));
1680 for (int i = m_blurEffects.size(); i < itemsAmount; i++) {
1681 auto blurEffect = qobject_cast<QQuickShaderEffect*>(blurComponent.create());
1682 blurEffect->setParent(q);
1683 blurEffect->setParentItem(q);
1684 auto sourceVariant = QVariant::fromValue<QQuickItem*>(blurEffect);
1685 QString sourceProperty = QStringLiteral("blurSrc%1").arg(i + 1);
1686 m_shaderEffect->setProperty(sourceProperty.toUtf8(), sourceVariant);
1687 // Initial value to avoid "'source' does not have a matching property" warning.
1688 // Will be updated with the correct one few lines forward.
1689 blurEffect->setProperty("source", sourceVariant);
1691 priv->layer()->setEnabled(true);
1692 priv->layer()->setSmooth(true);
1693 blurEffect->setVertexShader(blurVs);
1694 blurEffect->setFragmentShader(blurFs);
1695 m_blurEffects << blurEffect;
1696 }
1697 }
1698
1699 // Set the blur items source components
1700 if (!m_dummyShaderSource)
1701 m_dummyShaderSource = new QQuickShaderEffectSource(q);
1702 for (int i = 0; i < m_blurEffects.size(); i++) {
1703 auto *blurEffect = m_blurEffects[i];
1704 auto sourceItem = (i >= itemsAmount) ?
1705 static_cast<QQuickItem *>(m_dummyShaderSource) : (i == 0) ?
1706 static_cast<QQuickItem *>(m_shaderSource->output()) :
1707 static_cast<QQuickItem *>(m_blurEffects[i - 1]);
1708 auto sourceVariant = QVariant::fromValue<QQuickItem*>(sourceItem);
1709 blurEffect->setProperty("source", sourceVariant);
1710 }
1711}
1712
1714{
1715 Q_Q(QQuickMultiEffect);
1716 if (!m_shaderEffect || !m_shaderSource)
1717 return;
1718
1719 const bool blurItemsNeeded = (m_blurEnabled || m_shadowEnabled) && (m_blurMax > 0);
1720 const int itemPadding = m_autoPaddingEnabled && blurItemsNeeded ? m_blurMax * (1.0 + m_blurMultiplier) : 0;
1721
1722 // Set the shader effect size
1723 if (m_paddingRect != QRectF() || itemPadding > 0) {
1724 QRectF effectRect(-m_paddingRect.x() - itemPadding,
1725 -m_paddingRect.y() - itemPadding,
1726 q->width() + m_paddingRect.x() + m_paddingRect.width() + (itemPadding * 2),
1727 q->height() + m_paddingRect.y() + m_paddingRect.height() + (itemPadding * 2));
1728 m_shaderEffect->setX(effectRect.x());
1729 m_shaderEffect->setY(effectRect.y());
1730 m_shaderEffect->setWidth(effectRect.width());
1731 m_shaderEffect->setHeight(effectRect.height());
1732
1733 // Set the source size
1734 m_shaderSource->setSize(m_shaderEffect->size());
1735
1736 // When m_sourceItem is set and has size, use that as the base size.
1737 // When effect is used as a component in Item "layer.effect", source
1738 // doesn't have a size and then we follow the effect item size.
1739 const qreal baseWidth = m_sourceItem && m_sourceItem->width() > 0 ? m_sourceItem->width() : q->width();
1740 const qreal baseHeight = m_sourceItem && m_sourceItem->height() > 0 ? m_sourceItem->height() : q->height();
1741
1742 // Set the source rect
1743 const qreal widthMultiplier = q->width() > 0 ? baseWidth / q->width() : 1.0;
1744 const qreal heightMultiplier = q->height() > 0 ? baseHeight / q->height() : 1.0;
1745 const qreal xPadding = itemPadding * widthMultiplier;
1746 const qreal yPadding = itemPadding * heightMultiplier;
1747 QRectF rect = QRectF(m_paddingRect.x() * widthMultiplier,
1748 m_paddingRect.y() * heightMultiplier,
1749 m_paddingRect.width() * widthMultiplier,
1750 m_paddingRect.height() * heightMultiplier);
1751 QRectF sourceRect = QRectF(-rect.x() - xPadding,
1752 -rect.y() - yPadding,
1753 baseWidth + rect.x() + rect.width() + xPadding * 2,
1754 baseHeight + rect.y() + rect.height() + yPadding * 2);
1755 m_shaderSource->setSourceRect(sourceRect);
1756 } else {
1757 m_shaderEffect->setX(0);
1758 m_shaderEffect->setY(0);
1759 m_shaderEffect->setSize(q->size());
1760 m_shaderSource->setSize(q->size());
1761 m_shaderSource->setSourceRect(QRectF());
1762 }
1763
1767 Q_EMIT q->paddingRectChanged();
1768 Q_EMIT q->itemRectChanged();
1769 Q_EMIT q->itemSizeChanged();
1770}
1771
1773{
1774 if (!m_shaderSource)
1775 return;
1776
1777 auto sourceVariant = QVariant::fromValue<QQuickItem*>(m_shaderSource->output());
1778 m_shaderEffect->setProperty("src", sourceVariant);
1779
1780 // Force updating the blur items since the source output has changed
1781 updateBlurLevel(true);
1784}
1785
1787{
1788 if (!m_shaderSource)
1789 return;
1790
1791 m_shaderSource->polish();
1792}
1793
1795
1796#include "moc_qquickmultieffect_p.cpp"
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
float greenF() const noexcept
Returns the green color component of this color.
Definition qcolor.cpp:1643
float redF() const noexcept
Returns the red color component of this color.
Definition qcolor.cpp:1611
float alphaF() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1497
float blueF() const noexcept
Returns the blue color component of this color.
Definition qcolor.cpp:1675
void setSourceRect(const QRectF &sourceRect)
void setInput(QQuickItem *input)
bool isActive() const
QQuickItem * output
void activeChanged()
void outputChanged()
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object's name property to value.
The QQmlComponent class encapsulates a QML component definition.
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void setSize(const QSizeF &size)
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
void setParentItem(QQuickItem *parent)
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
void setHeight(qreal)
virtual QRectF boundingRect() const
Returns the extents of the item in its own coordinate system: a rectangle from {0,...
QSizeF size() const
qreal width
This property holds the width of this item.
Definition qquickitem.h:75
virtual void itemChange(ItemChange, const ItemChangeData &)
Called when change occurs for this item.
qreal height
This property holds the height of this item.
Definition qquickitem.h:76
void setWidth(qreal)
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:144
void setX(qreal)
void setY(qreal)
void polish()
Schedules a polish event for this item.
void setShadowOpacity(qreal shadowOpacity)
void setShadowColor(const QColor &color)
void setMaskSpreadAtMax(qreal spread)
void setColorizationColor(const QColor &color)
void setMaskThresholdMin(qreal threshold)
void setColorization(qreal colorization)
void setShadowVerticalOffset(qreal offset)
void handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
void setSource(QQuickItem *item)
void setShadowBlur(qreal shadowBlur)
void setMaskSource(QQuickItem *item)
QQuickItem * source() const
void setShadowScale(qreal shadowScale)
void setMaskThresholdMax(qreal threshold)
void setShadowEnabled(bool enabled)
void setMaskSpreadAtMin(qreal spread)
void setBlurEnabled(bool enabled)
QQuickItem * maskSource() const
void setSaturation(qreal saturation)
void updateBlurLevel(bool forceUpdate=false)
void setMaskInverted(bool inverted)
void setBlurMultiplier(qreal blurMultiplier)
void setShadowHorizontalOffset(qreal offset)
float calculateLod(float blurAmount)
void getBlurWeights(float blurLod, QVector4D &blurWeight1, QVector2D &blurWeight2)
void setPaddingRect(const QRectF &rect)
void setContrast(qreal contrast)
void updateBlurItemSizes(bool forceUpdate=false)
void setBrightness(qreal brightness)
void updateBlurItemsAmount(int blurLevel)
void handleGeometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
void setAutoPaddingEnabled(bool enabled)
void setMaskEnabled(bool enabled)
void setShadowHorizontalOffset(qreal offset)
void setMaskEnabled(bool enabled)
void setBrightness(qreal brightness)
void setPaddingRect(const QRectF &rect)
void setShadowEnabled(bool enabled)
void setShadowOpacity(qreal shadowOpacity)
void setContrast(qreal contrast)
void setMaskSpreadAtMin(qreal spread)
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
void hasProxySourceChanged()
void setMaskThresholdMin(qreal threshold)
void setMaskInverted(bool inverted)
void setMaskThresholdMax(qreal threshold)
void setMaskSpreadAtMax(qreal spread)
void setSource(QQuickItem *item)
void setShadowBlur(qreal shadowBlur)
void setColorizationColor(const QColor &color)
void setShadowScale(qreal shadowScale)
void setAutoPaddingEnabled(bool enabled)
void setMaskSource(QQuickItem *item)
void setShadowColor(const QColor &color)
void setBlurMultiplier(qreal blurMultiplier)
void setBlurMax(int blurMax)
void setBlurEnabled(bool enabled)
void setSaturation(qreal saturation)
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
void setColorization(qreal colorization)
void setShadowVerticalOffset(qreal offset)
void setBlur(qreal blur)
void itemChange(ItemChange change, const ItemChangeData &value) override
Called when change occurs for this item.
void setFragmentShader(const QUrl &fileUrl)
void setVertexShader(const QUrl &fileUrl)
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:672
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:669
constexpr QSizeF size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:735
\inmodule QtCore
Definition qsize.h:208
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:332
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:335
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
\inmodule QtCore
Definition qurl.h:94
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
The QVector4D class represents a vector or vertex in 4D space.
Definition qvectornd.h:330
rect
[4]
Combined button and popup list for selecting options.
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:289
static QPointF centerOffset(const QSizeF &screenSize, const QRectF &visibleArea)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
static const QMetaObjectPrivate * priv(const uint *data)
GLsizei const GLfloat * v
[13]
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLuint color
[2]
GLenum GLuint GLintptr offset
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
GLenum GLenum GLenum GLenum GLenum scale
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:80
void forceUpdate(QQuickItem *item)
SSL_CTX int void * arg
#define QStringLiteral(str)
#define Q_EMIT
#define emit
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:187
#define enabled
QGraphicsItem * item
QJSEngine engine
[0]
\inmodule QtQuick
Definition qquickitem.h:159