Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquick3dobject_p.h
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// Qt-Security score:significant reason:default
4
5
6#ifndef QSSGOBJECT_P_H
7#define QSSGOBJECT_P_H
8
9//
10// W A R N I N G
11// -------------
12//
13// This file is not part of the Qt API. It exists purely as an
14// implementation detail. This header file may change from version to
15// version without notice, or even be removed.
16//
17// We mean it.
18//
19
20#include "qquick3dobject.h"
21
23
25
27
28#include <private/qobject_p.h>
29#include <private/qquickstate_p.h>
30#include <private/qqmlnotifier_p.h>
31#include <private/qlazilyallocated_p.h>
32#include <private/qssgrendergraphobject_p.h>
33#include <QtQuick3DUtils/private/qquick3dprofiler_p.h>
34
35#include <QtCore/qpointer.h>
36
37QT_BEGIN_NAMESPACE
38
39class QQuick3DItem2D;
40
41class Q_QUICK3D_EXPORT QQuick3DObjectPrivate : public QObjectPrivate
42{
43 Q_DECLARE_PUBLIC(QQuick3DObject)
44public:
45 using Type = QSSGRenderGraphObject::Type;
46
47 enum class Flags : quint32
48 {
49 None = 0x0,
50 RequiresSecondaryUpdate = 0x1, // Only relevant for resources
51 };
52
53 /*!
54 Flags::RequiresSecondaryUpdate indicates that the object needs a secondary update, meaning an
55 additional call to updateSpatialNode() will be made after the first one. This is useful for objects
56 that depend on other objects being fully updated before they can update themselves properly, as
57 when the second call happens all objects have had their first updateSpatialNode() called.
58 In addition to setting this flag the object must also call requestSecondaryUpdate() when it knows
59 that it needs the secondary update!
60
61 NOTE: This flag is only relevant for resource objects, spatial nodes will be ignored.
62 */
63
64 using FlagsT = std::underlying_type_t<Flags>;
65
66 struct ConnectionKey
67 {
68 using Handle = void (QQuick3DObject::*)(QObject *);
69 QObject *context = nullptr;
70 Handle unusable = nullptr;
71 friend bool operator==(const ConnectionKey &a, const ConnectionKey &b) noexcept { return (a.context == b.context) && (a.unusable == b.unusable); }
72 };
73 using ConnectionMap = QHash<ConnectionKey, QMetaObject::Connection>;
74
75 template<typename SceneContext, typename CallContext, typename Setter>
76 static void attachWatcherPriv(SceneContext *sceneContext, CallContext *callContext, Setter setter, QQuick3DObject *newO, QObject *oldO)
77 {
78 static_assert(std::is_base_of_v<QQuick3DObject, SceneContext>, "The scene context must be a QQuick3DObject");
79 static_assert(std::is_member_function_pointer_v<Setter>, "The assumption is that the setter is a member function!");
80 static_assert(sizeof(ConnectionKey::Handle) >= sizeof(Setter), "The handle needs to be able to store the value of the setter");
81 // Sanity check: Make sure we have a valid context. If the sceneContext != callContext and we're here because the
82 // watched object just got destroyed by the parent (QObject dtor) and that parent also is used as the sceneContext
83 // then there's nothing more to do; all involved parties are being destroyed, so just bail out.
84 const bool validContext = static_cast<QObject *>(sceneContext) != static_cast<QObject *>(callContext) ? qobject_cast<QQuick3DObject *>(sceneContext) != nullptr : true;
85 if (validContext) {
86 auto sceneManager = QQuick3DObjectPrivate::get(sceneContext)->sceneManager;
87 auto &connectionMap = QQuick3DObjectPrivate::get(sceneContext)->connectionMap;
88 union
89 {
90 Setter s;
91 ConnectionKey::Handle h;
92 }; s = setter;
93 ConnectionKey key{static_cast<QObject *>(callContext), h};
94 // disconnect previous destruction listener
95 if (oldO) {
96 // NOTE: If the old object is inside the QObject's dtor (e.g., QObject::destroyed) we can't
97 // call deref (and there's no point anymore either).
98 if (auto old3dO = qobject_cast<QQuick3DObject *>(oldO))
99 QQuick3DObjectPrivate::derefSceneManager(old3dO);
100
101 auto it = connectionMap.constFind(key);
102 if (it != connectionMap.cend()) {
103 QObject::disconnect(*it);
104 connectionMap.erase(it);
105 }
106 }
107
108 // Watch new object
109 if (newO) {
110 if (sceneManager)
111 QQuick3DObjectPrivate::refSceneManager(newO, *sceneManager);
112 auto connection = QObject::connect(newO, &QObject::destroyed, callContext, [callContext, setter](){ (callContext->*setter)(nullptr); });
113 connectionMap.insert(key, connection);
114 }
115 }
116 }
117
118 /*!
119 Attach a object-destroyed-watcher to an object that's not owned.
120 There are few checks here just to keep it simple
121 (The compiler should still fail with a varying degree of helpful messages when used incorrectly).
122
123 \a sceneContext - ususally the same as the callContext and only different if the calledContext is a non-QQuick3DObject class
124 (as is the case for QQuick3DShaderUtilsTextureInput)!
125 \a callContext - The object watching another object
126 \a setter - The function/slot that is called for the object (context).
127 \a newO - The new object being watched
128 \b oldO - The previous object that should no longer be watched.
129
130 Note: The \a setter is a function that takes one argument with a discardable return value.
131 */
132 template<typename Context, typename Setter, typename Object3D>
133 static void attachWatcher(Context *context, Setter setter, Object3D *newO, Object3D *oldO)
134 {
135 attachWatcherPriv(context, context, setter, newO, oldO);
136 }
137
138 static QQuick3DObjectPrivate *get(QQuick3DObject *item) { return item->d_func(); }
139 static const QQuick3DObjectPrivate *get(const QQuick3DObject *item) { return item->d_func(); }
140 static QSSGRenderGraphObject *updateSpatialNode(QQuick3DObject *o, QSSGRenderGraphObject *n) { return o->updateSpatialNode(n); }
141
142 explicit QQuick3DObjectPrivate(Type t, FlagsT f);
143 explicit QQuick3DObjectPrivate(Type t, Flags f);
144 explicit QQuick3DObjectPrivate(Type t);
145 ~QQuick3DObjectPrivate() override;
146 void init(QQuick3DObject *parent);
147
148 QQmlListProperty<QObject> data();
149 QQmlListProperty<QObject> resources();
150 QQmlListProperty<QQuick3DObject> children();
151
152 QQmlListProperty<QQuickState> states();
153 QQmlListProperty<QQuickTransition> transitions();
154
155 QString state() const;
156 void setState(const QString &);
157
158 // data property
159 static void data_append(QQmlListProperty<QObject> *, QObject *);
160 static qsizetype data_count(QQmlListProperty<QObject> *);
161 static QObject *data_at(QQmlListProperty<QObject> *, qsizetype);
162 static void data_clear(QQmlListProperty<QObject> *);
163
164 // resources property
165 static QObject *resources_at(QQmlListProperty<QObject> *, qsizetype);
166 static void resources_append(QQmlListProperty<QObject> *, QObject *);
167 static qsizetype resources_count(QQmlListProperty<QObject> *);
168 static void resources_clear(QQmlListProperty<QObject> *);
169
170 // children property
171 static void children_append(QQmlListProperty<QQuick3DObject> *, QQuick3DObject *);
172 static qsizetype children_count(QQmlListProperty<QQuick3DObject> *);
173 static QQuick3DObject *children_at(QQmlListProperty<QQuick3DObject> *, qsizetype);
174 static void children_clear(QQmlListProperty<QQuick3DObject> *);
175
176 void _q_resourceObjectDeleted(QObject *);
177 void _q_cleanupContentItem2D();
178 quint64 _q_createJSWrapper(QQmlV4ExecutionEnginePtr engine);
179
180 enum ChangeType {
181 Geometry = 0x01,
182 SiblingOrder = 0x02,
183 Visibility = 0x04,
184 Opacity = 0x08,
185 Destroyed = 0x10,
186 Parent = 0x20,
187 Children = 0x40,
188 Rotation = 0x80,
189 ImplicitWidth = 0x100,
190 ImplicitHeight = 0x200,
191 Enabled = 0x400,
192 };
193
194 Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
195
196 struct ChangeListener
197 {
198 using ChangeTypes = QQuick3DObjectPrivate::ChangeTypes;
199
200 ChangeListener(QQuick3DObjectChangeListener *l = nullptr, ChangeTypes t = {}) : listener(l), types(t) {}
201
202 ChangeListener(QQuick3DObjectChangeListener *l) : listener(l), types(Geometry) {}
203
204 bool operator==(const ChangeListener &other) const
205 {
206 return listener == other.listener && types == other.types;
207 }
208
209 QQuick3DObjectChangeListener *listener;
210 ChangeTypes types;
211 };
212
213 struct ExtraData
214 {
215 ExtraData();
216
217 int hideRefCount;
218 QObjectList resourcesList;
219
220 };
221 QLazilyAllocated<ExtraData> extra;
222
223 QVector<QQuick3DObjectPrivate::ChangeListener> changeListeners;
224
225 void addItemChangeListener(QQuick3DObjectChangeListener *listener, ChangeTypes types);
226 void updateOrAddItemChangeListener(QQuick3DObjectChangeListener *listener, ChangeTypes types);
227 void removeItemChangeListener(QQuick3DObjectChangeListener *, ChangeTypes types);
228
229 QQuickStateGroup *_states();
230 QQuickStateGroup *_stateGroup;
231
232 enum DirtyType {
233 TransformOrigin = 0x00000001,
234 Transform = 0x00000002,
235 BasicTransform = 0x00000004,
236 Position = 0x00000008,
237 Size = 0x00000010,
238
239 ZValue = 0x00000020,
240 Content = 0x00000040,
241 Smooth = 0x00000080,
242 OpacityValue = 0x00000100,
243 ChildrenChanged = 0x00000200,
244 ChildrenStackingChanged = 0x00000400,
245 ParentChanged = 0x00000800,
246
247 Clip = 0x00001000,
248 Window = 0x00002000,
249
250 EffectReference = 0x00008000,
251 Visible = 0x00010000,
252 HideReference = 0x00020000,
253 Antialiasing = 0x00040000,
254
255 InstanceRootChanged = 0x00080000,
256 // When you add an attribute here, don't forget to update
257 // dirtyToString()
258
259 TransformUpdateMask = TransformOrigin | Transform | BasicTransform | Position | Window,
260 ComplexTransformUpdateMask = Transform | Window,
261 ContentUpdateMask = Size | Content | Smooth | Window | Antialiasing,
262 ChildrenUpdateMask = ChildrenChanged | ChildrenStackingChanged | EffectReference | Window
263 };
264
265 quint32 dirtyAttributes;
266 QString dirtyToString() const;
267 void dirty(DirtyType);
268 void addToDirtyList();
269 void removeFromDirtyList();
270 QQuick3DObject *nextDirtyItem;
271 QQuick3DObject **prevDirtyItem;
272
273 bool hasFlag(Flags flag) { return (flags & FlagsT(flag)) != 0; }
274
275 void setCulled(bool);
276
277 QPointer<QQuick3DSceneManager> sceneManager;
278 int sceneRefCount;
279
280 QQuick3DObject *parentItem;
281
282 QList<QQuick3DObject *> childItems;
283 void addChild(QQuick3DObject *);
284 void removeChild(QQuick3DObject *);
285 void siblingOrderChanged();
286
287 void refSceneManager(QQuick3DSceneManager &);
288 void derefSceneManager();
289
290 static void refSceneManager(QQuick3DObject *obj, QQuick3DSceneManager &mgr)
291 {
292 if (obj)
293 QQuick3DObjectPrivate::get(obj)->refSceneManager(mgr);
294 }
295 static void derefSceneManager(QQuick3DObject *obj)
296 {
297 if (obj)
298 QQuick3DObjectPrivate::get(obj)->derefSceneManager();
299 }
300
301 QQuick3DObject *subFocusItem;
302 void updateSubFocusItem(QQuick3DObject *scope, bool focus);
303
304 void itemChange(QQuick3DObject::ItemChange, const QQuick3DObject::ItemChangeData &);
305
306 virtual void updatePolish() {}
307
308 void requestSecondaryUpdate() { secondaryUpdateRequested = true; }
309
310 QSSGRenderGraphObject *spatialNode = nullptr;
311
312 Type type = Type::Unknown;
313 FlagsT flags = FlagsT(Flags::None);
314 bool secondaryUpdateRequested = false;
315 bool componentComplete = true;
316 bool preSyncNeeded = false;
317 bool culled;
318 bool sharedResource = false;
319 QQuick3DItem2D *contentItem2d = nullptr;
320 ConnectionMap connectionMap;
321 Q_QUICK3D_PROFILE_ID
322};
323
324Q_DECLARE_OPERATORS_FOR_FLAGS(QQuick3DObjectPrivate::ChangeTypes)
325Q_DECLARE_TYPEINFO(QQuick3DObjectPrivate::ChangeListener, Q_PRIMITIVE_TYPE);
327
328inline size_t qHash(const QQuick3DObjectPrivate::ConnectionKey &con, size_t seed = 0) noexcept
329{
330 return qHashBits(&con, sizeof(QQuick3DObjectPrivate::ConnectionKey), seed);
331}
332
333QT_END_NAMESPACE
334
335#endif // QSSGOBJECT_P_H
Combined button and popup list for selecting options.
Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_RELOCATABLE_TYPE)
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept
Definition qsize.h:192