Qt 6.x
The Qt SDK
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
166{
167}
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
787{
788 Q_D(const QQuickMultiEffect);
789 return d->itemRect();
790}
791
799{
800 Q_D(const QQuickMultiEffect);
801 return d->fragmentShader();
802}
803
811{
812 Q_D(const QQuickMultiEffect);
813 return d->vertexShader();
814}
815
827{
828 Q_D(const QQuickMultiEffect);
829 return d->hasProxySource();
830}
831
832// *** protected ***
833
835{
838 d->initialize();
839}
840
841void QQuickMultiEffect::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
842{
844 QQuickItem::geometryChange(newGeometry, oldGeometry);
845 if (width() > 0 && height() > 0)
846 d->handleGeometryChange(newGeometry, oldGeometry);
847}
848
850{
852 d->handleItemChange(change, value);
854}
855
856// *** private ***
857
859{
860}
861
863{
864}
865
866void QQuickMultiEffectPrivate::handleGeometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
867{
868 Q_UNUSED(oldGeometry);
869 Q_UNUSED(newGeometry);
870 initialize();
871 if (!m_shaderEffect)
872 return;
875}
876
878{
880 if (change == QQuickItem::ItemSceneChange)
881 initialize();
882}
883
884
886{
887 return m_sourceItem;
888}
889
891{
893 if (item == m_sourceItem)
894 return;
895
896 m_sourceItem = item;
897 if (m_shaderSource)
898 m_shaderSource->setInput(m_sourceItem);
899
901 q->update();
902 Q_EMIT q->sourceChanged();
903}
904
906{
907 return m_autoPaddingEnabled;
908}
909
911{
913 if (enabled == m_autoPaddingEnabled)
914 return;
915
916 m_autoPaddingEnabled = enabled;
918 q->update();
919 Q_EMIT q->autoPaddingEnabledChanged();
920}
921
923{
924 return m_paddingRect;
925}
926
928{
930 if (rect == m_paddingRect)
931 return;
932 m_paddingRect = rect;
935 q->update();
936 emit q->paddingRectChanged();
937}
938
940{
941 return m_brightness;
942}
943
945{
947 if (brightness == m_brightness)
948 return;
949
950 m_brightness = brightness;
951 if (m_shaderEffect)
952 m_shaderEffect->setProperty("brightness", m_brightness);
953
954 q->update();
955 Q_EMIT q->brightnessChanged();
956}
957
959{
960 return m_contrast;
961}
962
964{
966 if (contrast == m_contrast)
967 return;
968
969 m_contrast = contrast;
970 if (m_shaderEffect)
971 m_shaderEffect->setProperty("contrast", m_contrast);
972
973 q->update();
974 Q_EMIT q->contrastChanged();
975}
976
978{
979 return m_saturation;
980}
981
983{
985 if (saturation == m_saturation)
986 return;
987
988 m_saturation = saturation;
989 if (m_shaderEffect)
990 m_shaderEffect->setProperty("saturation", m_saturation);
991
992 q->update();
993 Q_EMIT q->saturationChanged();
994}
995
997{
998 return m_colorization;
999}
1000
1002{
1003 Q_Q(QQuickMultiEffect);
1004 if (colorization == m_colorization)
1005 return;
1006
1007 m_colorization = colorization;
1009
1010 q->update();
1011 Q_EMIT q->colorizationChanged();
1012}
1013
1015{
1016 return m_colorizationColor;
1017}
1018
1020{
1021 Q_Q(QQuickMultiEffect);
1022 if (color == m_colorizationColor)
1023 return;
1024
1025 m_colorizationColor = color;
1027
1028 q->update();
1029 Q_EMIT q->colorizationColorChanged();
1030}
1031
1033{
1034 return m_blurEnabled;
1035}
1036
1038{
1039 Q_Q(QQuickMultiEffect);
1040 if (enabled == m_blurEnabled)
1041 return;
1042
1043 m_blurEnabled = enabled;
1047
1048 q->update();
1049 Q_EMIT q->blurEnabledChanged();
1050}
1051
1053{
1054 return m_blur;
1055}
1056
1058{
1059 Q_Q(QQuickMultiEffect);
1060 if (blur == m_blur)
1061 return;
1062
1063 m_blur = blur;
1065
1066 q->update();
1067 Q_EMIT q->blurChanged();
1068}
1069
1071{
1072 return m_blurMax;
1073}
1074
1076{
1077 Q_Q(QQuickMultiEffect);
1078 if (blurMax == m_blurMax)
1079 return;
1080
1081 m_blurMax = blurMax;
1088
1089 q->update();
1090 Q_EMIT q->blurMaxChanged();
1091}
1092
1094{
1095 return m_blurMultiplier;
1096}
1097
1099{
1100 Q_Q(QQuickMultiEffect);
1101 if (blurMultiplier == m_blurMultiplier)
1102 return;
1103
1104 m_blurMultiplier = blurMultiplier;
1106 updateBlurItemSizes(true);
1109
1110 q->update();
1111 Q_EMIT q->blurMultiplierChanged();
1112}
1113
1115{
1116 return m_shadowEnabled;
1117}
1118
1120{
1121 Q_Q(QQuickMultiEffect);
1122 if (enabled == m_shadowEnabled)
1123 return;
1124
1125 m_shadowEnabled = enabled;
1129
1130 q->update();
1131 Q_EMIT q->shadowEnabledChanged();
1132}
1133
1135{
1136 return m_shadowOpacity;
1137}
1138
1140{
1141 Q_Q(QQuickMultiEffect);
1142 if (shadowOpacity == m_shadowOpacity)
1143 return;
1144
1145 m_shadowOpacity = shadowOpacity;
1147
1148 q->update();
1149 Q_EMIT q->shadowOpacityChanged();
1150}
1151
1153{
1154 return m_shadowBlur;
1155}
1156
1158{
1159 Q_Q(QQuickMultiEffect);
1160 if (shadowBlur == m_shadowBlur)
1161 return;
1162
1163 m_shadowBlur = shadowBlur;
1165
1166 q->update();
1167 Q_EMIT q->shadowBlurChanged();
1168}
1169
1171{
1172 return m_shadowHorizontalOffset;
1173}
1174
1176{
1177 Q_Q(QQuickMultiEffect);
1178 if (offset == m_shadowHorizontalOffset)
1179 return;
1180
1181 m_shadowHorizontalOffset = offset;
1183
1184 q->update();
1185 Q_EMIT q->shadowHorizontalOffsetChanged();
1186}
1187
1189{
1190 return m_shadowVerticalOffset;
1191}
1192
1194{
1195 Q_Q(QQuickMultiEffect);
1196 if (offset == m_shadowVerticalOffset)
1197 return;
1198
1199 m_shadowVerticalOffset = offset;
1201
1202 q->update();
1203 Q_EMIT q->shadowVerticalOffsetChanged();
1204}
1205
1207{
1208 return m_shadowColor;
1209}
1210
1212{
1213 Q_Q(QQuickMultiEffect);
1214 if (color == m_shadowColor)
1215 return;
1216
1217 m_shadowColor = color;
1219
1220 q->update();
1221 Q_EMIT q->shadowColorChanged();
1222}
1223
1225{
1226 return m_shadowScale;
1227}
1228
1230{
1231 Q_Q(QQuickMultiEffect);
1232 if (shadowScale == m_shadowScale)
1233 return;
1234
1235 m_shadowScale = shadowScale;
1237 if (m_shaderEffect)
1238 m_shaderEffect->setProperty("shadowScale", 1.0 / m_shadowScale);
1239
1240 q->update();
1241 Q_EMIT q->shadowScaleChanged();
1242}
1243
1245{
1246 return m_maskEnabled;
1247}
1248
1250{
1251 Q_Q(QQuickMultiEffect);
1252 if (enabled == m_maskEnabled)
1253 return;
1254
1255 m_maskEnabled = enabled;
1257
1258 q->update();
1259 Q_EMIT q->maskEnabledChanged();
1260}
1261
1263{
1264 return m_maskSourceItem;
1265}
1266
1268{
1269 Q_Q(QQuickMultiEffect);
1270 if (item == m_maskSourceItem)
1271 return;
1272
1273 m_maskSourceItem = item;
1274 if (m_shaderEffect) {
1275 auto maskSourceVariant = QVariant::fromValue<QQuickItem*>(m_maskSourceItem);
1276 m_shaderEffect->setProperty("maskSrc", maskSourceVariant);
1277 }
1278
1279 q->update();
1280 Q_EMIT q->maskSourceChanged();
1281}
1282
1284{
1285 return m_maskThresholdMin;
1286}
1287
1289{
1290 Q_Q(QQuickMultiEffect);
1291 if (threshold == m_maskThresholdMin)
1292 return;
1293
1294 m_maskThresholdMin = threshold;
1296
1297 q->update();
1298 Q_EMIT q->maskThresholdMinChanged();
1299}
1300
1302{
1303 return m_maskSpreadAtMin;
1304}
1305
1307{
1308 Q_Q(QQuickMultiEffect);
1309 if (spread == m_maskSpreadAtMin)
1310 return;
1311
1312 m_maskSpreadAtMin = spread;
1314
1315 q->update();
1316 Q_EMIT q->maskSpreadAtMinChanged();
1317}
1318
1320{
1321 return m_maskThresholdMax;
1322}
1323
1325{
1326 Q_Q(QQuickMultiEffect);
1327 if (threshold == m_maskThresholdMax)
1328 return;
1329
1330 m_maskThresholdMax = threshold;
1332
1333 q->update();
1334 Q_EMIT q->maskThresholdMaxChanged();
1335}
1336
1338{
1339 return m_maskSpreadAtMax;
1340}
1341
1343{
1344 Q_Q(QQuickMultiEffect);
1345 if (spread == m_maskSpreadAtMax)
1346 return;
1347
1348 m_maskSpreadAtMax = spread;
1350
1351 q->update();
1352 Q_EMIT q->maskSpreadAtMaxChanged();
1353}
1354
1356{
1357 return m_maskInverted;
1358}
1359
1361{
1362 Q_Q(QQuickMultiEffect);
1363 if (inverted == m_maskInverted)
1364 return;
1365
1366 m_maskInverted = inverted;
1367 if (m_shaderEffect)
1368 m_shaderEffect->setProperty("maskInverted", float(m_maskInverted));
1369
1370 q->update();
1371 Q_EMIT q->maskInvertedChanged();
1372}
1373
1375{
1376 if (!m_shaderEffect || !m_shaderSource)
1377 return QRectF();
1378
1379 QRectF sourceRect = m_shaderSource->sourceRect();
1380 if (sourceRect.width() > 0 && sourceRect.height() > 0)
1381 return sourceRect;
1382 else
1383 return m_shaderEffect->boundingRect();
1384}
1385
1387{
1388 return m_fragShader;
1389}
1390
1392{
1393 return m_vertShader;
1394}
1395
1397{
1398 return m_shaderSource && m_shaderSource->isActive();
1399}
1400
1401// This initializes the component. It will be ran once, when
1402// the component is ready and it has a valid size.
1404{
1405 Q_Q(QQuickMultiEffect);
1406 if (m_initialized)
1407 return;
1408 if (!q->isComponentComplete())
1409 return;
1410 if (!q->window())
1411 return;
1412 if (q->width() <= 0 || q->height() <= 0)
1413 return;
1414
1415 m_shaderEffect = new QQuickShaderEffect(q);
1416 m_shaderSource = new QGfxSourceProxy(q);
1417 QObject::connect(m_shaderSource, &QGfxSourceProxy::outputChanged, q, [this] { proxyOutputChanged(); });
1419
1420 m_shaderEffect->setParentItem(q);
1421 m_shaderEffect->setSize(q->size());
1422
1423 m_shaderSource->setParentItem(q);
1424 m_shaderSource->setSize(q->size());
1425 m_shaderSource->setInput(m_sourceItem);
1426
1434
1435 // Create properties
1436 auto sourceVariant = QVariant::fromValue<QQuickItem*>(m_shaderSource->output());
1437 m_shaderEffect->setProperty("src", sourceVariant);
1438 m_shaderEffect->setProperty("brightness", m_brightness);
1439 m_shaderEffect->setProperty("contrast", m_contrast);
1440 m_shaderEffect->setProperty("saturation", m_saturation);
1441 m_shaderEffect->setProperty("shadowScale", 1.0 / m_shadowScale);
1442 auto maskSourceVariant = QVariant::fromValue<QQuickItem*>(m_maskSourceItem);
1443 m_shaderEffect->setProperty("maskSrc", maskSourceVariant);
1444 m_shaderEffect->setProperty("maskInverted", float(m_maskInverted));
1445
1449
1451
1452 m_initialized = true;
1453}
1454
1456{
1457 if (!m_shaderEffect)
1458 return;
1459
1460 // Calculate threshold and spread values for mask
1461 // smoothstep, keeping always edge0 < edge1.
1462 const qreal c0 = 0.0001;
1463 const qreal c1 = 1.0 - c0;
1464 const qreal mt1 = m_maskThresholdMin + c0;
1465 const qreal ms1 = m_maskSpreadAtMin + 1.0;
1466 const qreal mt2 = c1 - m_maskThresholdMax;
1467 const qreal ms2 = m_maskSpreadAtMax + 1.0;
1468 const QVector4D maskThresholdSpread = QVector4D(
1469 mt1 * ms1 - (ms1 - c1),
1470 mt1 * ms1,
1471 mt2 * ms2 - (ms2 - c1),
1472 mt2 * ms2);
1473 m_shaderEffect->setProperty("mask", maskThresholdSpread);
1474}
1475
1477{
1478 if (!m_shaderEffect)
1479 return;
1480
1481 const qreal scale = 1.0 / m_shadowScale;
1482 QVector2D centerOffset((1.0 - scale) * (0.5 + 0.5 * (m_paddingRect.x() - m_paddingRect.width()) / m_shaderEffect->width()),
1483 (1.0 - scale) * (0.5 + 0.5 * (m_paddingRect.y() - m_paddingRect.height()) / m_shaderEffect->height()));
1484 m_shaderEffect->setProperty("centerOffset", centerOffset);
1485}
1486
1488{
1489 if (!m_shaderEffect)
1490 return;
1491
1492 QVector2D shadowOffset = QVector2D(m_shadowHorizontalOffset / m_shaderEffect->width(), m_shadowVerticalOffset / m_shaderEffect->height());
1493 m_shaderEffect->setProperty("shadowOffset", shadowOffset);
1494}
1495
1497{
1498 if (!m_shaderEffect)
1499 return;
1500
1501 float alpha = std::clamp(float(m_colorizationColor.alphaF() * m_colorization), 0.0f, 1.0f);
1502 QVector4D colorizationColor(m_colorizationColor.redF(),
1503 m_colorizationColor.greenF(),
1504 m_colorizationColor.blueF(),
1505 alpha);
1506 m_shaderEffect->setProperty("colorizationColor", colorizationColor);
1507}
1508
1510{
1511 if (!m_shaderEffect)
1512 return;
1513
1514 float alpha = std::clamp(float(m_shadowColor.alphaF() * m_shadowOpacity), 0.0f, 1.0f);
1515 QVector4D shadowColor(m_shadowColor.redF(),
1516 m_shadowColor.greenF(),
1517 m_shadowColor.blueF(),
1518 alpha);
1519
1520 m_shaderEffect->setProperty("shadowColor", shadowColor);
1521}
1522
1524{
1525 return qSqrt(blurAmount * float(m_blurMax) / 64.0f) * 1.2f - 0.2f;
1526}
1527
1529{
1530 return std::max(0.0f, std::min(1.0f, 1.0f - v * 2.0f));
1531}
1532
1533void QQuickMultiEffectPrivate::getBlurWeights(float blurLod, QVector4D &blurWeight1, QVector2D &blurWeight2)
1534{
1535 float bw1 = blurWeight(std::fabs(blurLod - 0.1f));
1536 float bw2 = blurWeight(std::fabs(blurLod - 0.3f));
1537 float bw3 = blurWeight(std::fabs(blurLod - 0.5f));
1538 float bw4 = blurWeight(std::fabs(blurLod - 0.7f));
1539 float bw5 = blurWeight(std::fabs(blurLod - 0.9f));
1540 float bw6 = blurWeight(std::fabs(blurLod - 1.1f));
1541 float bsum = bw1 + bw2 + bw3 + bw4 + bw5 + bw6;
1542 blurWeight1 = QVector4D(bw1 / bsum, bw2 / bsum, bw3 / bsum, bw4 / bsum);
1543 blurWeight2 = QVector2D(bw5 / bsum, bw6 / bsum);
1544}
1545
1547{
1548 if (!m_shaderEffect)
1549 return;
1550 float blurLod = calculateLod(m_blur);
1551 getBlurWeights(blurLod, m_blurWeight1, m_blurWeight2);
1552 m_shaderEffect->setProperty("blurWeight1", m_blurWeight1);
1553 m_shaderEffect->setProperty("blurWeight2", m_blurWeight2);
1554}
1555
1557{
1558 if (!m_shaderEffect)
1559 return;
1560 float blurLod = calculateLod(m_shadowBlur);
1561 getBlurWeights(blurLod, m_shadowBlurWeight1, m_shadowBlurWeight2);
1562 m_shaderEffect->setProperty("shadowBlurWeight1", m_shadowBlurWeight1);
1563 m_shaderEffect->setProperty("shadowBlurWeight2", m_shadowBlurWeight2);
1564}
1565
1567{
1568 if (m_blurEffects.isEmpty() || !m_shaderSource || !m_sourceItem)
1569 return;
1570
1571 // First blur item size to be half of th source item
1572 // extended size, rounded to next divisible by 16.
1573 QSizeF sourceSize = itemRect().size();
1574 QSizeF firstItemSize(std::ceil(sourceSize.width() / 16) * 8,
1575 std::ceil(sourceSize.height() / 16) * 8);
1576
1577 if (!forceUpdate && m_firstBlurItemSize == firstItemSize)
1578 return;
1579
1580 qCDebug(lcQuickEffect) << "Source size:" << sourceSize;
1581 m_firstBlurItemSize = firstItemSize;
1582
1583 for (int i = 0; i < m_blurEffects.size(); i++) {
1584 auto *blurEffect = m_blurEffects[i];
1585 QSizeF itemSize = (i == 0) ? firstItemSize : m_blurEffects[i - 1]->size() * 0.5;
1586 qCDebug(lcQuickEffect) << "Blur item" << i << ":" << itemSize;
1587 blurEffect->setSize(itemSize);
1588
1589 const QVector2D offset((1.0 + m_blurMultiplier) / itemSize.width(),
1590 (1.0 + m_blurMultiplier) / itemSize.height());
1591 blurEffect->setProperty("offset", offset);
1592 }
1593}
1594
1596{
1597 Q_Q(QQuickMultiEffect);
1598 if (!q->isComponentComplete())
1599 return;
1600
1601 QString vShader = QStringLiteral("multieffect_c");
1602 if (m_shadowEnabled)
1603 vShader += QStringLiteral("s");
1604
1605 QString fShader = QStringLiteral("multieffect_c");
1606 if (m_maskEnabled)
1607 fShader += QStringLiteral("m");
1608 if (m_blurEnabled && m_blurMax > 0)
1609 fShader += QStringLiteral("b");
1610 if (m_shadowEnabled)
1611 fShader += QStringLiteral("s");
1612
1613 fShader += QString::number(m_blurLevel);
1614
1615 bool shaderChanged = false;
1616 if (fShader != m_fragShader) {
1617 shaderChanged = true;
1618 m_fragShader = fShader;
1619 QUrl fs = QUrl(QStringLiteral("qrc:/data/shaders/%1.frag.qsb").arg(m_fragShader));
1620 m_shaderEffect->setFragmentShader(fs);
1621 Q_EMIT q->fragmentShaderChanged();
1622 }
1623 if (vShader != m_vertShader) {
1624 shaderChanged = true;
1625 m_vertShader = vShader;
1626 QUrl vs = QUrl(QStringLiteral("qrc:/data/shaders/%1.vert.qsb").arg(m_vertShader));
1627 m_shaderEffect->setVertexShader(vs);
1628 Q_EMIT q->vertexShaderChanged();
1629 }
1630 if (shaderChanged) {
1631 qCDebug(lcQuickEffect) << this << "Shaders: " << m_fragShader << m_vertShader;
1632 Q_EMIT q->shaderChanged();
1633 }
1634}
1635
1637{
1638 int blurLevel = 0;
1639 if ((m_blurEnabled || m_shadowEnabled) && m_blurMax > 0) {
1640 if (m_blurMax > 32)
1641 blurLevel = 3;
1642 else if (m_blurMax > 16)
1643 blurLevel = 2;
1644 else
1645 blurLevel = 1;
1646 }
1647
1648 if (blurLevel != m_blurLevel || (blurLevel > 0 && m_blurEffects.isEmpty()) || forceUpdate) {
1649 // Blur level has changed or blur items need to be
1650 // initially created.
1651 updateBlurItemsAmount(blurLevel);
1652 // When the level grows, new items must be resized
1653 if (blurLevel > m_blurLevel)
1654 updateBlurItemSizes(true);
1655 }
1656 m_blurLevel = blurLevel;
1657}
1658
1660{
1661 Q_Q(QQuickMultiEffect);
1662 if (!m_shaderEffect)
1663 return;
1664
1665 // Lowest blur level uses 3 items, highest 5 items.
1666 int itemsAmount = blurLevel == 0 ? 0 : blurLevel + 2;
1667
1668 if (m_blurEffects.size() < itemsAmount) {
1669 // Add more blur items.
1670 // Note that by design blur items are only added and never reduced
1671 // during the lifetime of the effect component.
1672 const auto engine = qmlEngine(q);
1673 QUrl blurVs = QUrl(QStringLiteral("qrc:/data/shaders/bluritems.vert.qsb"));
1674 QUrl blurFs = QUrl(QStringLiteral("qrc:/data/shaders/bluritems.frag.qsb"));
1675 QQmlComponent blurComponent(engine, QUrl(QStringLiteral("qrc:/data/BlurItem.qml")));
1676 for (int i = m_blurEffects.size(); i < itemsAmount; i++) {
1677 auto blurEffect = qobject_cast<QQuickShaderEffect*>(blurComponent.create());
1678 blurEffect->setParent(q);
1679 blurEffect->setParentItem(q);
1680 auto sourceVariant = QVariant::fromValue<QQuickItem*>(blurEffect);
1681 QString sourceProperty = QStringLiteral("blurSrc%1").arg(i + 1);
1682 m_shaderEffect->setProperty(sourceProperty.toUtf8(), sourceVariant);
1683 // Initial value to avoid "'source' does not have a matching property" warning.
1684 // Will be updated with the correct one few lines forward.
1685 blurEffect->setProperty("source", sourceVariant);
1687 priv->layer()->setEnabled(true);
1688 priv->layer()->setSmooth(true);
1689 blurEffect->setVertexShader(blurVs);
1690 blurEffect->setFragmentShader(blurFs);
1691 m_blurEffects << blurEffect;
1692 }
1693 }
1694
1695 // Set the blur items source components
1696 static const auto dummyShaderSource = new QQuickShaderEffectSource(q);
1697 for (int i = 0; i < m_blurEffects.size(); i++) {
1698 auto *blurEffect = m_blurEffects[i];
1699 auto sourceItem = (i >= itemsAmount) ?
1700 static_cast<QQuickItem *>(dummyShaderSource) : (i == 0) ?
1701 static_cast<QQuickItem *>(m_shaderSource->output()) :
1702 static_cast<QQuickItem *>(m_blurEffects[i - 1]);
1703 auto sourceVariant = QVariant::fromValue<QQuickItem*>(sourceItem);
1704 blurEffect->setProperty("source", sourceVariant);
1705 }
1706}
1707
1709{
1710 Q_Q(QQuickMultiEffect);
1711 if (!m_shaderEffect || !m_shaderSource)
1712 return;
1713
1714 const bool blurItemsNeeded = (m_blurEnabled || m_shadowEnabled) && (m_blurMax > 0);
1715 const int itemPadding = m_autoPaddingEnabled && blurItemsNeeded ? m_blurMax * (1.0 + m_blurMultiplier) : 0;
1716
1717 // Set the shader effect size
1718 if (m_paddingRect != QRectF() || itemPadding > 0) {
1719 QRectF effectRect(-m_paddingRect.x() - itemPadding,
1720 -m_paddingRect.y() - itemPadding,
1721 q->width() + m_paddingRect.x() + m_paddingRect.width() + (itemPadding * 2),
1722 q->height() + m_paddingRect.y() + m_paddingRect.height() + (itemPadding * 2));
1723 m_shaderEffect->setX(effectRect.x());
1724 m_shaderEffect->setY(effectRect.y());
1725 m_shaderEffect->setWidth(effectRect.width());
1726 m_shaderEffect->setHeight(effectRect.height());
1727
1728 // Set the source size
1729 m_shaderSource->setSize(m_shaderEffect->size());
1730
1731 // When m_sourceItem is set and has size, use that as the base size.
1732 // When effect is used as a component in Item "layer.effect", source
1733 // doesn't have a size and then we follow the effect item size.
1734 const qreal baseWidth = m_sourceItem && m_sourceItem->width() > 0 ? m_sourceItem->width() : q->width();
1735 const qreal baseHeight = m_sourceItem && m_sourceItem->height() > 0 ? m_sourceItem->height() : q->height();
1736
1737 // Set the source rect
1738 const qreal widthMultiplier = q->width() > 0 ? baseWidth / q->width() : 1.0;
1739 const qreal heightMultiplier = q->height() > 0 ? baseHeight / q->height() : 1.0;
1740 const qreal xPadding = itemPadding * widthMultiplier;
1741 const qreal yPadding = itemPadding * heightMultiplier;
1742 QRectF rect = QRectF(m_paddingRect.x() * widthMultiplier,
1743 m_paddingRect.y() * heightMultiplier,
1744 m_paddingRect.width() * widthMultiplier,
1745 m_paddingRect.height() * heightMultiplier);
1746 QRectF sourceRect = QRectF(-rect.x() - xPadding,
1747 -rect.y() - yPadding,
1748 baseWidth + rect.x() + rect.width() + xPadding * 2,
1749 baseHeight + rect.y() + rect.height() + yPadding * 2);
1750 m_shaderSource->setSourceRect(sourceRect);
1751 } else {
1752 m_shaderEffect->setX(0);
1753 m_shaderEffect->setY(0);
1754 m_shaderEffect->setSize(q->size());
1755 m_shaderSource->setSize(q->size());
1756 m_shaderSource->setSourceRect(QRectF());
1757 }
1758
1762 Q_EMIT q->paddingRectChanged();
1763 Q_EMIT q->itemRectChanged();
1764 Q_EMIT q->itemSizeChanged();
1765}
1766
1768{
1769 if (!m_shaderSource)
1770 return;
1771
1772 auto sourceVariant = QVariant::fromValue<QQuickItem*>(m_shaderSource->output());
1773 m_shaderEffect->setProperty("src", sourceVariant);
1774
1775 // Force updating the blur items since the source output has changed
1776 updateBlurLevel(true);
1779}
1780
1782{
1783 if (!m_shaderSource)
1784 return;
1785
1786 m_shaderSource->polish();
1787}
1788
1790
1791#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:2823
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.
virtual QObject * create(QQmlContext *context=nullptr)
Create an object instance from this component, within the specified context.
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:64
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:76
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:77
void setWidth(qreal)
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:143
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:483
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:658
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:655
constexpr QSizeF size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:721
\inmodule QtCore
Definition qsize.h:207
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:321
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:324
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
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:7822
QByteArray toUtf8() const &
Definition qstring.h:563
\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:243
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
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:76
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:92
#define enabled
QGraphicsItem * item
QJSEngine engine
[0]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
\inmodule QtQuick
Definition qquickitem.h:158