Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qquick3dtexture.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qquick3dtexture_p.h"
5#include <QtQuick3DRuntimeRender/private/qssgrenderimage_p.h>
6#include <QtQuick3DRuntimeRender/private/qssgrendertexturedata_p.h>
7#include <QtQuick3DRuntimeRender/private/qssgrenderloadedtexture_p.h>
8#include <QtQml/QQmlFile>
9#include <QtQuick/QQuickItem>
10#include <QtQuick/private/qquickitem_p.h>
11#include <QtCore/qmath.h>
12
13#include "qquick3dobject_p.h"
15#include "qquick3dutils_p.h"
16
18
92{
93}
94
97{
98 const QMetaObject *mo = metaObject();
99 const int updateSlotIdx = mo->indexOfSlot("update()");
100 if (updateSlotIdx >= 0)
101 m_updateSlot = mo->method(updateSlotIdx);
102 if (!m_updateSlot.isValid())
103 qWarning("QQuick3DTexture: Failed to find update() slot");
104}
105
107{
108 if (m_layer) {
109 if (m_sceneManagerForLayer)
110 m_sceneManagerForLayer->qsgDynamicTextures.removeAll(m_layer);
111 m_layer->deleteLater(); // uhh...
112 }
113
114 if (m_sourceItem) {
115 QQuickItemPrivate *sourcePrivate = QQuickItemPrivate::get(m_sourceItem);
117 }
118}
119
157{
158 return m_source;
159}
160
206{
207 return m_sourceItem;
208}
209
231{
232 return m_scaleU;
233}
234
256{
257 return m_scaleV;
258}
259
283{
284 return m_mappingMode;
285}
286
301{
302 return m_tilingModeHorizontal;
303}
304
320{
321 return m_tilingModeVertical;
322}
323
342{
343 return m_rotationUV;
344}
345
363{
364 return m_positionU;
365}
366
388{
389 return m_positionV;
390}
391
410{
411 return m_pivotU;
412}
413
432{
433 return m_pivotV;
434}
435
453{
454 return m_flipU;
455}
456
474{
475 return m_flipV;
476}
477
488{
489 return m_indexUV;
490}
491
508{
509 return m_magFilter;
510}
511
528{
529 return m_minFilter;
530}
531
549{
550 return m_mipFilter;
551}
552
567{
568 return m_textureData;
569}
570
593{
594 return m_generateMipmaps;
595}
596
629{
630 return m_autoOrientation;
631}
632
634{
635 if (m_source == source)
636 return;
637
638 m_source = source;
639 m_dirtyFlags.setFlag(DirtyFlag::SourceDirty);
640 m_dirtyFlags.setFlag(DirtyFlag::SourceItemDirty);
641 m_dirtyFlags.setFlag(DirtyFlag::TextureDataDirty);
643 update();
644}
645
646void QQuick3DTexture::trySetSourceParent()
647{
648 if (m_sourceItem->parentItem() && m_sourceItemRefed)
649 return;
650
651 auto *sourcePrivate = QQuickItemPrivate::get(m_sourceItem);
652
653 if (!m_sourceItem->parentItem()) {
654 if (const auto &manager = QQuick3DObjectPrivate::get(this)->sceneManager) {
655 if (auto *window = manager->window()) {
656 if (m_sourceItemRefed) {
657 // Item was already refed but probably with hide set to false...
658 // so we need to deref before we ref again below.
659 const bool hide = m_sourceItemReparented;
660 sourcePrivate->derefFromEffectItem(hide);
661 m_sourceItemRefed = false;
662 }
663
664 m_sourceItem->setParentItem(window->contentItem());
665 m_sourceItemReparented = true;
666 update();
667 }
668 }
669 }
670
671 if (!m_sourceItemRefed) {
672 const bool hide = m_sourceItemReparented;
673 sourcePrivate->refFromEffectItem(hide);
674 }
675}
676
678{
679 if (m_sourceItem == sourceItem)
680 return;
681
682 disconnect(m_textureProviderConnection);
683 disconnect(m_textureUpdateConnection);
684
685 if (m_sourceItem) {
686 QQuickItemPrivate *sourcePrivate = QQuickItemPrivate::get(m_sourceItem);
687
688 const bool hide = m_sourceItemReparented;
689 sourcePrivate->derefFromEffectItem(hide);
690 m_sourceItemRefed = false;
691
693 disconnect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
694 if (m_sourceItemReparented) {
695 m_sourceItem->setParentItem(nullptr);
696 m_sourceItemReparented = false;
697 }
698 }
699
700 m_sourceItem = sourceItem;
701
702 if (sourceItem) {
703 trySetSourceParent();
704 QQuickItemPrivate *sourcePrivate = QQuickItemPrivate::get(m_sourceItem);
706 connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
707 sourcePrivate->ensureSubsceneDeliveryAgent();
708 }
709
710 if (m_layer) {
712 manager->qsgDynamicTextures.removeAll(m_layer);
713 m_sceneManagerForLayer = nullptr;
714 // cannot touch m_layer here
715 }
716 m_initializedSourceItem = nullptr;
717 m_initializedSourceItemSize = QSize();
718
719 m_dirtyFlags.setFlag(DirtyFlag::SourceDirty);
720 m_dirtyFlags.setFlag(DirtyFlag::SourceItemDirty);
721 m_dirtyFlags.setFlag(DirtyFlag::TextureDataDirty);
723 update();
724}
725
727{
728 if (qFuzzyCompare(m_scaleU, scaleU))
729 return;
730
731 m_scaleU = scaleU;
732 m_dirtyFlags.setFlag(DirtyFlag::TransformDirty);
734 update();
735}
736
738{
739 if (qFuzzyCompare(m_scaleV, scaleV))
740 return;
741
742 m_scaleV = scaleV;
743 m_dirtyFlags.setFlag(DirtyFlag::TransformDirty);
745 update();
746}
747
749{
750 if (m_mappingMode == mappingMode)
751 return;
752
753 m_mappingMode = mappingMode;
755 update();
756}
757
759{
760 if (m_tilingModeHorizontal == tilingModeHorizontal)
761 return;
762
763 m_tilingModeHorizontal = tilingModeHorizontal;
765 update();
766}
767
769{
770 if (m_tilingModeVertical == tilingModeVertical)
771 return;
772
773 m_tilingModeVertical = tilingModeVertical;
775 update();
776}
777
778void QQuick3DTexture::setRotationUV(float rotationUV)
779{
780 if (qFuzzyCompare(m_rotationUV, rotationUV))
781 return;
782
783 m_rotationUV = rotationUV;
784 m_dirtyFlags.setFlag(DirtyFlag::TransformDirty);
786 update();
787}
788
789void QQuick3DTexture::setPositionU(float positionU)
790{
791 if (qFuzzyCompare(m_positionU, positionU))
792 return;
793
794 m_positionU = positionU;
795 m_dirtyFlags.setFlag(DirtyFlag::TransformDirty);
797 update();
798}
799
800void QQuick3DTexture::setPositionV(float positionV)
801{
802 if (qFuzzyCompare(m_positionV, positionV))
803 return;
804
805 m_positionV = positionV;
806 m_dirtyFlags.setFlag(DirtyFlag::TransformDirty);
808 update();
809}
810
812{
813 if (qFuzzyCompare(m_pivotU, pivotU))
814 return;
815
816 m_pivotU = pivotU;
817 m_dirtyFlags.setFlag(DirtyFlag::TransformDirty);
819 update();
820}
821
823{
824 if (qFuzzyCompare(m_pivotV, pivotV))
825 return;
826
827 m_pivotV = pivotV;
828 m_dirtyFlags.setFlag(DirtyFlag::TransformDirty);
830 update();
831}
832
834{
835 if (m_flipU == flipU)
836 return;
837
838 m_flipU = flipU;
839 m_dirtyFlags.setFlag(DirtyFlag::TransformDirty);
841 update();
842}
843
845{
846 if (m_flipV == flipV)
847 return;
848
849 m_flipV = flipV;
850 m_dirtyFlags.setFlag(DirtyFlag::FlipVDirty);
852 update();
853}
854
856{
857 if (m_indexUV == indexUV)
858 return;
859
860 if (indexUV < 0)
861 m_indexUV = 0;
862 else if (indexUV > 1)
863 m_indexUV = 1;
864 else
865 m_indexUV = indexUV;
866
867 m_dirtyFlags.setFlag(DirtyFlag::IndexUVDirty);
869 update();
870}
871
873{
874 if (m_textureData == textureData)
875 return;
876
877 // Make sure to disconnect if the geometry gets deleted out from under us
879
880 if (m_textureData)
881 QObject::disconnect(m_textureDataConnection);
882 m_textureData = textureData;
883
884 if (m_textureData) {
885 m_textureDataConnection
887 markDirty(DirtyFlag::TextureDataDirty);
888 });
889 }
890
891 m_dirtyFlags.setFlag(DirtyFlag::SourceDirty);
892 m_dirtyFlags.setFlag(DirtyFlag::SourceItemDirty);
893 m_dirtyFlags.setFlag(DirtyFlag::TextureDataDirty);
895 update();
896}
897
898void QQuick3DTexture::setGenerateMipmaps(bool generateMipmaps)
899{
900 if (m_generateMipmaps == generateMipmaps)
901 return;
902
903 m_generateMipmaps = generateMipmaps;
904 m_dirtyFlags.setFlag(DirtyFlag::SamplerDirty);
906 update();
907}
908
909void QQuick3DTexture::setAutoOrientation(bool autoOrientation)
910{
911 if (m_autoOrientation == autoOrientation)
912 return;
913
914 m_autoOrientation = autoOrientation;
915 m_dirtyFlags.setFlag(DirtyFlag::FlipVDirty);
917 update();
918}
919
921{
922 if (m_magFilter == magFilter)
923 return;
924
925 m_magFilter = magFilter;
926 m_dirtyFlags.setFlag(DirtyFlag::SamplerDirty);
928 update();
929}
930
932{
933 if (m_minFilter == minFilter)
934 return;
935
936 m_minFilter = minFilter;
937 m_dirtyFlags.setFlag(DirtyFlag::SamplerDirty);
939 update();
940}
941
943{
944 if (m_mipFilter == mipFilter)
945 return;
946
947 m_mipFilter = mipFilter;
948 m_dirtyFlags.setFlag(DirtyFlag::SamplerDirty);
950 update();
951}
952
953// this function may involve file system access and hence can be expensive
954bool QQuick3DTexture::effectiveFlipV(const QSSGRenderImage &imageNode) const
955{
956 // No magic when autoOrientation is false.
957 if (!m_autoOrientation)
958 return m_flipV;
959
960 // Keep the same order as in QSSGBufferManager: sourceItem > textureData > source
961
962 // Using sourceItem implies inverting (the effective, internal) flipV,
963 // transparently to the user. Otherwise two #Rectangle models textured with
964 // two Textures where one has its content loaded from an image file via
965 // QImage while the other is generated by Qt Quick rendering into the
966 // texture would appear upside-down relative to each other, and that
967 // discrepancy is not ideal. (that said, this won't help CustomMaterial, as
968 // documented for flipV and co.)
969
970 if (m_sourceItem)
971 return !m_flipV;
972
973 // With textureData we assume the application knows what it is doing,
974 // because there the application is controlling the content itself.
975
976 if (m_textureData)
977 return m_flipV;
978
979 // Compressed textures (or any texture that is coming from the associated
980 // container formats, such as KTX, i.e. not via QImage but through
981 // QTextureFileReader) get the implicit flip, like sourceItem. This is done
982 // mainly for parity with Qt Quick's Image, see QTBUG-93972.
983
984 if (!m_source.isEmpty()) {
985 const QString filePath = imageNode.m_imagePath.path();
986 if (!filePath.isEmpty()) {
988 if (QSSGInputUtil::getStreamForTextureFile(filePath, true, nullptr, &fileType)) {
990 return !m_flipV;
991 }
992 }
993 }
994
995 return m_flipV;
996}
997
999{
1000 if (context && url.isRelative()) {
1001 QString path = url.path();
1002 QChar separator = QChar::fromLatin1(';');
1003 if (path.contains(separator)) {
1004 QString resolvedPath;
1005 const QStringList paths = path.split(separator);
1006 bool first = true;
1007 for (auto &s : paths) {
1008 auto mapped = QQmlFile::urlToLocalFileOrQrc(context->resolvedUrl(s));
1009 if (!first)
1010 resolvedPath.append(separator);
1011 resolvedPath.append(mapped);
1012 first = false;
1013 }
1014 return QSSGRenderPath(resolvedPath);
1015 }
1016 }
1018}
1019
1021{
1022 if (!node) {
1023 markAllDirty();
1025 }
1027 auto imageNode = static_cast<QSSGRenderImage *>(node);
1028
1029 if (m_dirtyFlags.testFlag(DirtyFlag::TransformDirty)) {
1030 m_dirtyFlags.setFlag(DirtyFlag::TransformDirty, false);
1031
1032 // flipV and indexUV have their own dirty flags, handled separately below
1033 imageNode->m_flipU = m_flipU;
1034 imageNode->m_scale = QVector2D(m_scaleU, m_scaleV);
1035 imageNode->m_pivot = QVector2D(m_pivotU, m_pivotV);
1036 imageNode->m_rotation = m_rotationUV;
1037 imageNode->m_position = QVector2D(m_positionU, m_positionV);
1038
1040 }
1041
1042 bool nodeChanged = false;
1043 if (m_dirtyFlags.testFlag(DirtyFlag::SourceDirty)) {
1044 m_dirtyFlags.setFlag(DirtyFlag::SourceDirty, false);
1045 m_dirtyFlags.setFlag(DirtyFlag::FlipVDirty, true);
1046 if (!m_source.isEmpty()) {
1047 const QQmlContext *context = qmlContext(this);
1048 imageNode->m_imagePath = resolveImagePath(m_source, context);
1049 } else {
1050 imageNode->m_imagePath = QSSGRenderPath();
1051 }
1052 nodeChanged = true;
1053 }
1054 if (m_dirtyFlags.testFlag(DirtyFlag::IndexUVDirty)) {
1055 m_dirtyFlags.setFlag(DirtyFlag::IndexUVDirty, false);
1056 imageNode->m_indexUV = m_indexUV;
1057 }
1058 nodeChanged |= qUpdateIfNeeded(imageNode->m_mappingMode,
1059 QSSGRenderImage::MappingModes(m_mappingMode));
1060 nodeChanged |= qUpdateIfNeeded(imageNode->m_horizontalTilingMode,
1061 QSSGRenderTextureCoordOp(m_tilingModeHorizontal));
1062 nodeChanged |= qUpdateIfNeeded(imageNode->m_verticalTilingMode,
1063 QSSGRenderTextureCoordOp(m_tilingModeVertical));
1064
1065 if (m_dirtyFlags.testFlag(DirtyFlag::SamplerDirty)) {
1066 m_dirtyFlags.setFlag(DirtyFlag::SamplerDirty, false);
1067 nodeChanged |= qUpdateIfNeeded(imageNode->m_minFilterType,
1068 QSSGRenderTextureFilterOp(m_minFilter));
1069 nodeChanged |= qUpdateIfNeeded(imageNode->m_magFilterType,
1070 QSSGRenderTextureFilterOp(m_magFilter));
1071 nodeChanged |= qUpdateIfNeeded(imageNode->m_mipFilterType,
1072 QSSGRenderTextureFilterOp(m_mipFilter));
1073 nodeChanged |= qUpdateIfNeeded(imageNode->m_generateMipmaps,
1074 m_generateMipmaps);
1075 }
1076
1077 if (m_dirtyFlags.testFlag(DirtyFlag::TextureDataDirty)) {
1078 m_dirtyFlags.setFlag(DirtyFlag::TextureDataDirty, false);
1079 m_dirtyFlags.setFlag(DirtyFlag::FlipVDirty, true);
1080 if (m_textureData)
1081 imageNode->m_rawTextureData = static_cast<QSSGRenderTextureData *>(QQuick3DObjectPrivate::get(m_textureData)->spatialNode);
1082 else
1083 imageNode->m_rawTextureData = nullptr;
1084 nodeChanged = true;
1085 }
1086
1087 if (m_dirtyFlags.testFlag(DirtyFlag::SourceItemDirty)) {
1088 m_dirtyFlags.setFlag(DirtyFlag::SourceItemDirty, false);
1089 m_dirtyFlags.setFlag(DirtyFlag::FlipVDirty, true);
1090 if (m_sourceItem) {
1091 QQuickWindow *window = m_sourceItem->window();
1092 // If it was an inline declared item (very common, e.g. Texture {
1093 // sourceItem: Rectangle { ... } } then it is likely it won't be
1094 // associated with a window (Qt Quick scene) unless we help it to
1095 // one via refWindow. However, this here is only the last resort,
1096 // ideally there is a refWindow upon ItemSceneChange already.
1097 if (!window) {
1099 if (window)
1100 QQuickItemPrivate::get(m_sourceItem)->refWindow(window);
1101 else
1102 qWarning("Unable to get window, this will probably not work");
1103 }
1104
1105 // This assumes that the QSGTextureProvider returned never changes,
1106 // which is hopefully the case for both Image and Item layers.
1107 if (QSGTextureProvider *provider = m_sourceItem->textureProvider()) {
1108 imageNode->m_qsgTexture = provider->texture();
1109
1110 disconnect(m_textureProviderConnection);
1111 m_textureProviderConnection = connect(provider, &QSGTextureProvider::textureChanged, this, [this, provider] () {
1112 // called on the render thread, if there is one; the gui
1113 // thread may or may not be blocked (e.g. if the source is
1114 // a View3D, that emits textureChanged() from preprocess,
1115 // so after sync, whereas an Image emits in
1116 // updatePaintNode() where gui is blocked)
1117 auto imageNode = static_cast<QSSGRenderImage *>(QQuick3DObjectPrivate::get(this)->spatialNode);
1118 if (!imageNode)
1119 return;
1120
1121 imageNode->m_qsgTexture = provider->texture();
1122 // the QSGTexture may be different now, go through loadRenderImage() again
1123 imageNode->m_flags.setFlag(QSSGRenderImage::Flag::Dirty);
1124 // Call update() on the main thread - otherwise we could
1125 // end up in a situation where the 3D scene does not update
1126 // due to nothing else changing, even though the source
1127 // texture is now different.
1128 m_updateSlot.invoke(this, Qt::AutoConnection);
1130
1131 disconnect(m_textureUpdateConnection);
1132 auto *sourcePrivate = QQuickItemPrivate::get(m_sourceItem);
1133 if (sourcePrivate->window) {
1134 QQuickItem *sourceItem = m_sourceItem; // for capturing, recognizing in the lambda that m_sourceItem has changed is essential
1135
1136 // Why after, not beforeSynchronizing? Consider the case of an Item layer:
1137 // if the View3D gets to sync (updatePaintNode) first, doing an
1138 // updateTexture() is futile, the QSGLayer is not yet initialized (not
1139 // associated with an Item, has no size, etc.). That happens only once the
1140 // underlying QQuickShaderEffectSource hits its updatePaintNode. And that
1141 // may well happen happen only after the View3D has finished with its sync
1142 // step. By connecting to afterSynchronizing, we still get a chance to
1143 // trigger a layer texture update and so have a QSGTexture with real
1144 // content ready by the time the View3D prepares/renders the 3D scene upon
1145 // the scenegraph's preprocess step (Offscreen) or before/after the
1146 // scenegraph rendering (if Underlay/Overlay).
1147 //
1148 // This eliminates, or in the worst case reduces, the ugly effects of not
1149 // having a texture ready when rendering the 3D scene.
1150
1151 m_textureUpdateConnection = connect(sourcePrivate->window, &QQuickWindow::afterSynchronizing, this, [this, sourceItem]() {
1152 // Called on the render thread with gui blocked (if there is a render thread, that is).
1153 if (m_sourceItem != sourceItem) {
1154 disconnect(m_textureProviderConnection);
1155 disconnect(m_textureUpdateConnection);
1156 return;
1157 }
1158 auto imageNode = static_cast<QSSGRenderImage *>(QQuick3DObjectPrivate::get(this)->spatialNode);
1159 if (!imageNode)
1160 return;
1161
1162 if (QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(imageNode->m_qsgTexture)) {
1163 if (t->updateTexture())
1164 update(); // safe because the gui thread is blocked
1165 }
1167 } else {
1168 qWarning("No window for item, texture updates are doomed");
1169 }
1170
1171 if (m_layer) {
1172 delete m_layer;
1173 m_layer = nullptr;
1174 }
1175 } else {
1176 // Not a texture provider, so not an Image or an Item with
1177 // layer.enabled: true, create our own QSGLayer.
1178 if (m_initializedSourceItem != m_sourceItem || m_initializedSourceItemSize != m_sourceItem->size()) {
1179 // If there was a previous sourceItem and m_layer is valid
1180 // then set its content to null until we get to
1181 // afterSynchronizing, otherwise things can blow up.
1182 if (m_layer)
1183 m_layer->setItem(nullptr);
1184
1185 m_initializedSourceItem = m_sourceItem;
1186 m_initializedSourceItemSize = m_sourceItem->size();
1187
1188 // The earliest next point where we can do anything is
1189 // after the scenegraph's QQuickItem sync round has completed.
1190 connect(window, &QQuickWindow::afterSynchronizing, this, [this, window]() {
1191 auto imageNode = static_cast<QSSGRenderImage *>(QQuick3DObjectPrivate::get(this)->spatialNode);
1192 if (!imageNode)
1193 return;
1194
1195 // Called on the render thread with gui blocked (if there is a render thread, that is).
1196 disconnect(window, &QQuickWindow::afterSynchronizing, this, nullptr);
1197 if (m_layer) {
1198 const auto &manager = QQuick3DObjectPrivate::get(this)->sceneManager;
1199 manager->qsgDynamicTextures.removeAll(m_layer);
1200 delete m_layer;
1201 m_layer = nullptr;
1202 }
1203
1204 QQuickItemPrivate *sourcePrivate = QQuickItemPrivate::get(m_sourceItem);
1205 QSGRenderContext *rc = sourcePrivate->sceneGraphRenderContext();
1206 Q_ASSERT(QThread::currentThread() == rc->thread()); // must be on the render thread
1208 connect(sourcePrivate->window, SIGNAL(sceneGraphInvalidated()), layer, SLOT(invalidated()), Qt::DirectConnection);
1209
1211 manager->qsgDynamicTextures << layer;
1212 m_sceneManagerForLayer = manager;
1213
1215 {
1216 // this is on the render thread so all borked threading-wise (all data here is gui thread stuff...) but will survive
1217 manager->qsgDynamicTextures.removeAll(layer);
1219
1220 QQuickItem *sourceItem = m_sourceItem; // for capturing, recognizing in the lambda that m_sourceItem has changed is essential
1221 connect(layer, &QObject::destroyed, this, [this, sourceItem]()
1222 {
1223 // just as dubious as the previous connection
1224 if (m_initializedSourceItem == sourceItem) {
1225 m_sceneManagerForLayer = nullptr;
1226 m_initializedSourceItem = nullptr;
1227 }
1229
1230 // With every frame try to update the texture. Use
1231 // afterSynchronizing like in the other branch. (why
1232 // after: a property changing something in the 2D
1233 // subtree leading to updates in the content will only
1234 // be "visible" after the (2D item) sync, not before)
1235 //
1236 // If updateTexture() returns false, content hasn't
1237 // changed. This complements qsgDynamicTextures and
1238 // QQuick3DViewport::updateDynamicTextures().
1239 m_textureUpdateConnection = connect(sourcePrivate->window, &QQuickWindow::afterSynchronizing,
1240 this, [this, sourceItem]()
1241 {
1242 // Called on the render thread with gui blocked (if there is a render thread, that is).
1243 if (!m_layer)
1244 return;
1245 if (m_sourceItem != sourceItem) {
1246 disconnect(m_textureUpdateConnection);
1247 return;
1248 }
1249 if (m_layer->updateTexture())
1250 update();
1252
1253 m_layer = layer;
1254 m_layer->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode());
1255
1256 QRectF sourceRect = QRectF(0, 0, m_sourceItem->width(), m_sourceItem->height());
1257 if (qFuzzyIsNull(sourceRect.width()))
1258 sourceRect.setWidth(256);
1259 if (qFuzzyIsNull(sourceRect.height()))
1260 sourceRect.setHeight(256);
1261 m_layer->setRect(sourceRect);
1262
1263 QSize textureSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height())));
1264 const QSize minTextureSize = sourcePrivate->sceneGraphContext()->minimumFBOSize();
1265 while (textureSize.width() < minTextureSize.width())
1266 textureSize.rwidth() *= 2;
1267 while (textureSize.height() < minTextureSize.height())
1268 textureSize.rheight() *= 2;
1269 m_layer->setSize(textureSize);
1270
1271 // now that the layer has an item and a size, it can render into the texture
1272 m_layer->updateTexture();
1273
1274 imageNode->m_qsgTexture = m_layer;
1275 imageNode->m_flags.setFlag(QSSGRenderImage::Flag::Dirty);
1277 }
1278 }
1279 } else {
1280 if (m_layer) {
1281 m_layer->setItem(nullptr);
1282 delete m_layer;
1283 m_layer = nullptr;
1284 }
1285 imageNode->m_qsgTexture = nullptr;
1286 }
1287 nodeChanged = true;
1288 }
1289
1290 if (m_dirtyFlags.testFlag(DirtyFlag::FlipVDirty)) {
1291 m_dirtyFlags.setFlag(DirtyFlag::FlipVDirty, false);
1292 imageNode->m_flipV = effectiveFlipV(*imageNode);
1294 }
1295
1296 if (nodeChanged)
1297 imageNode->m_flags.setFlag(QSSGRenderImage::Flag::Dirty);
1298
1299 return imageNode;
1300}
1301
1302void QQuick3DTexture::itemChange(QQuick3DObject::ItemChange change, const QQuick3DObject::ItemChangeData &value)
1303{
1305 if (change == QQuick3DObject::ItemChange::ItemSceneChange) {
1306 // Source item
1307 if (m_sourceItem) {
1308 disconnect(m_sceneManagerWindowChangeConnection);
1309
1310 if (m_sceneManagerForLayer) {
1311 m_sceneManagerForLayer->qsgDynamicTextures.removeOne(m_layer);
1312 m_sceneManagerForLayer = nullptr;
1313 }
1314 trySetSourceParent();
1315 const auto &sceneManager = value.sceneManager;
1316 Q_ASSERT(QQuick3DObjectPrivate::get(this)->sceneManager == sceneManager);
1317 if (m_layer) {
1318 if (sceneManager)
1319 sceneManager->qsgDynamicTextures << m_layer;
1320 m_sceneManagerForLayer = sceneManager;
1321 }
1322
1323 // If m_sourceItem was an inline declared item (very common, e.g.
1324 // Texture { sourceItem: Rectangle { ... } } then it is highly
1325 // likely it won't be associated with a window (Qt Quick scene)
1326 // yet. Associate with one as soon as possible, do not leave it to
1327 // updateSpatialNode, because that, while safe, would defer
1328 // rendering into the texture to a future frame (adding a 2 frame
1329 // lag for the first rendering of the mesh textured with the 2D
1330 // item content), since a refWindow needs to be followed by a
1331 // scenegraph sync round to get QSGNodes created (updatePaintNode),
1332 // whereas updateSpatialNode is in the middle of a sync round, so
1333 // would need to wait for another one, etc.
1334 if (sceneManager && m_sourceItem && !m_sourceItem->window()) {
1335 if (sceneManager->window()) {
1336 QQuickItemPrivate::get(m_sourceItem)->refWindow(sceneManager->window());
1337 } else {
1338 m_sceneManagerWindowChangeConnection = connect(sceneManager, &QQuick3DSceneManager::windowChanged, this,
1339 [this, sceneManager]
1340 {
1341 if (m_sourceItem && !m_sourceItem->window() && sceneManager->window())
1342 QQuickItemPrivate::get(m_sourceItem)->refWindow(sceneManager->window());
1343 });
1344 }
1345 }
1346 }
1347 // TextureData
1348 if (m_textureData) {
1349 const auto &sceneManager = value.sceneManager;
1350 if (sceneManager)
1351 QQuick3DObjectPrivate::refSceneManager(m_textureData, *sceneManager);
1352 else
1354 }
1355 }
1356}
1357
1359{
1360 Q_ASSERT(item == m_sourceItem);
1361 Q_UNUSED(item);
1362 Q_UNUSED(geometry);
1363 if (change.sizeChange()) {
1364 m_dirtyFlags.setFlag(DirtyFlag::SourceItemDirty);
1365 update();
1366 }
1367}
1368
1369void QQuick3DTexture::sourceItemDestroyed(QObject *item)
1370{
1371 Q_ASSERT(item == m_sourceItem);
1372 Q_UNUSED(item);
1373
1374 m_sourceItem = nullptr;
1375
1376 m_dirtyFlags.setFlag(DirtyFlag::SourceDirty);
1377 m_dirtyFlags.setFlag(DirtyFlag::SourceItemDirty);
1378 m_dirtyFlags.setFlag(DirtyFlag::TextureDataDirty);
1380 update();
1381}
1382
1383void QQuick3DTexture::markDirty(QQuick3DTexture::DirtyFlag type)
1384{
1385 if (!m_dirtyFlags.testFlag(type)) {
1386 m_dirtyFlags.setFlag(type, true);
1387 update();
1388 }
1389}
1390
1392{
1394 return static_cast<QSSGRenderImage *>(p->spatialNode);
1395}
1396
1398{
1399 m_dirtyFlags = DirtyFlags(0xFFFF);
1401}
1402
\inmodule QtCore
Definition qchar.h:48
static constexpr QChar fromLatin1(char c) noexcept
Converts the Latin-1 character c to its equivalent QChar.
Definition qchar.h:461
bool invoke(QObject *object, Qt::ConnectionType connectionType, QGenericReturnArgument returnValue, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument()) const
\obsolete [6.5] Please use the variadic overload of this function
bool isValid() const
\inmodule QtCore
Definition qobject.h:90
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
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1561
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to QFile.
Definition qqmlfile.cpp:643
QPointer< QQuick3DSceneManager > sceneManager
void refSceneManager(QQuick3DSceneManager &)
static QQuick3DObjectPrivate * get(QQuick3DObject *item)
QSSGRenderGraphObject * spatialNode
static void attachWatcher(Context *context, Setter setter, Object3D *newO, Object3D *oldO)
Attach a object-destroyed-watcher to an object that's not owned.
\qmltype Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DObject \inherits QtObject
virtual QSSGRenderGraphObject * updateSpatialNode(QSSGRenderGraphObject *node)
virtual void itemChange(ItemChange, const ItemChangeData &)
virtual void markAllDirty()
QVector< QSGDynamicTexture * > qsgDynamicTextures
\qmltype TextureData \inherits Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DTextureData
void setPivotV(float pivotV)
void setScaleV(float scaleV)
void setHorizontalTiling(QQuick3DTexture::TilingMode tilingModeHorizontal)
void setAutoOrientation(bool autoOrientation)
void minFilterChanged()
TilingMode tilingModeVertical
void setPivotU(float pivotU)
void sourceItemChanged()
void setRotationUV(float rotationUV)
void autoOrientationChanged()
void setTextureData(QQuick3DTextureData *textureData)
void setMipFilter(QQuick3DTexture::Filter mipFilter)
MappingMode mappingMode
TilingMode tilingModeHorizontal
void positionUChanged()
void setSourceItem(QQuickItem *sourceItem)
void itemChange(ItemChange change, const ItemChangeData &value) override
void horizontalTilingChanged()
void setVerticalTiling(QQuick3DTexture::TilingMode tilingModeVertical)
void verticalTilingChanged()
void magFilterChanged()
void markAllDirty() override
void setGenerateMipmaps(bool generateMipmaps)
void scaleUChanged()
QQuick3DTextureData * textureData
void pivotVChanged()
void generateMipmapsChanged()
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &geometry) override
void mipFilterChanged()
void setIndexUV(int indexUV)
void rotationUVChanged()
void setPositionU(float positionU)
void mappingModeChanged()
void setPositionV(float positionV)
~QQuick3DTexture() override
void setSource(const QUrl &source)
void setFlipV(bool flipV)
void indexUVChanged()
void scaleVChanged()
QQuick3DTexture(QQuick3DObject *parent=nullptr)
\qmltype Texture \inherits Object3D \inqmlmodule QtQuick3D
QSSGRenderGraphObject * updateSpatialNode(QSSGRenderGraphObject *node) override
void setMagFilter(QQuick3DTexture::Filter magFilter)
void pivotUChanged()
QQuickItem * sourceItem
void setMappingMode(QQuick3DTexture::MappingMode mappingMode)
QSSGRenderImage * getRenderImage()
void setMinFilter(QQuick3DTexture::Filter minFilter)
TilingMode verticalTiling() const
\qmlproperty enumeration QtQuick3D::Texture::tilingModeVertical
void setFlipU(bool flipU)
void setScaleU(float scaleU)
void positionVChanged()
void textureDataChanged()
void sourceChanged()
TilingMode horizontalTiling() const
\qmlproperty enumeration QtQuick3D::Texture::tilingModeHorizontal
QSGRenderContext * sceneGraphRenderContext() const
void removeItemChangeListener(QQuickItemChangeListener *, ChangeTypes types)
void derefFromEffectItem(bool unhide)
void addItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types)
QQuickWindow * window
void refWindow(QQuickWindow *)
QQuickDeliveryAgent * ensureSubsceneDeliveryAgent()
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 setParentItem(QQuickItem *parent)
virtual QSGTextureProvider * textureProvider() const
Returns the texture provider for an item.
QSizeF size() const
QQuickWindow * window() const
Returns the window in which this item is rendered.
qreal width
This property holds the width of this item.
Definition qquickitem.h:76
QQuickItem * parentItem() const
qreal height
This property holds the height of this item.
Definition qquickitem.h:77
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtCore\reentrant
Definition qrect.h:483
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 void setWidth(qreal w) noexcept
Sets the width of the rectangle to the given finite width.
Definition qrect.h:804
constexpr void setHeight(qreal h) noexcept
Sets the height of the rectangle to the given finite height.
Definition qrect.h:807
virtual QSGLayer * createLayer(QSGRenderContext *renderContext)=0
The QSGDynamicTexture class serves as a baseclass for dynamically changing textures,...
Definition qsgtexture.h:100
virtual bool updateTexture()=0
Call this function to explicitly update the dynamic texture.
virtual void setItem(QSGNode *item)=0
QSGContext * sceneGraphContext() const
The QSGTextureProvider class encapsulates texture based entities in QML.
void textureChanged()
This signal is emitted when the texture changes.
QString path() const
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:156
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:153
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QString & append(QChar c)
Definition qstring.cpp:3227
static QThread * currentThread()
Definition qthread.cpp:966
\inmodule QtCore
Definition qurl.h:94
bool isRelative() const
Returns true if the URL is relative; otherwise returns false.
Definition qurl.cpp:2797
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1888
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
Definition qurl.cpp:2465
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
auto mo
[7]
Combined button and popup list for selecting options.
@ AutoConnection
@ DirectConnection
static void * context
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputLayerEXT layer
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:287
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:303
#define qWarning
Definition qlogging.h:162
int qCeil(T v)
Definition qmath.h:36
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
GLenum type
GLsizei const GLuint * paths
GLint first
GLsizei GLsizei GLchar * source
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:71
static QSSGRenderPath resolveImagePath(const QUrl &url, const QQmlContext *context)
QT_BEGIN_NAMESPACE bool qUpdateIfNeeded(T &orig, T updated)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static const QSize minTextureSize
QSSGRenderTextureCoordOp
QSSGRenderTextureFilterOp
static FileType fileType(const QFileInfo &fi)
#define emit
#define Q_UNUSED(x)
if(qFloatDistance(a, b)<(1<< 7))
[0]
QUrl url("example.com")
[constructor-url-reference]
obj metaObject() -> className()
myObject disconnect()
[26]
QGraphicsItem * item
edit hide()
aWidget window() -> setWindowTitle("New Window Title")
[2]
QNetworkAccessManager manager
\inmodule QtCore
static QSharedPointer< QIODevice > getStreamForTextureFile(const QString &inPath, bool inQuiet=false, QString *outPath=nullptr, FileType *outFileType=nullptr)
QSSGRenderTextureFilterOp m_mipFilterType
MappingModes m_mappingMode
QSSGRenderPath m_imagePath
QSSGRenderTextureCoordOp m_horizontalTilingMode
QSSGRenderTextureFilterOp m_minFilterType
QSSGRenderTextureCoordOp m_verticalTilingMode
QSSGRenderTextureData * m_rawTextureData
QSSGRenderTextureFilterOp m_magFilterType
QSGTexture * m_qsgTexture
Definition moc.h:24
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent