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 QObject::disconnect(connectionMap.take(key));
102 }
103
104 // Watch new object
105 if (newO) {
106 if (sceneManager)
107 QQuick3DObjectPrivate::refSceneManager(newO, *sceneManager);
108 auto connection = QObject::connect(newO, &QObject::destroyed, callContext, [callContext, setter](){ (callContext->*setter)(nullptr); });
109 connectionMap.insert(key, connection);
110 }
111 }
112 }
113
114 /*!
115 Attach a object-destroyed-watcher to an object that's not owned.
116 There are few checks here just to keep it simple
117 (The compiler should still fail with a varying degree of helpful messages when used incorrectly).
118
119 \a sceneContext - ususally the same as the callContext and only different if the calledContext is a non-QQuick3DObject class
120 (as is the case for QQuick3DShaderUtilsTextureInput)!
121 \a callContext - The object watching another object
122 \a setter - The function/slot that is called for the object (context).
123 \a newO - The new object being watched
124 \b oldO - The previous object that should no longer be watched.
125
126 Note: The \a setter is a function that takes one argument with a discardable return value.
127 */
128 template<typename Context, typename Setter, typename Object3D>
129 static void attachWatcher(Context *context, Setter setter, Object3D *newO, Object3D *oldO)
130 {
131 attachWatcherPriv(context, context, setter, newO, oldO);
132 }
133
134 static QQuick3DObjectPrivate *get(QQuick3DObject *item) { return item->d_func(); }
135 static const QQuick3DObjectPrivate *get(const QQuick3DObject *item) { return item->d_func(); }
136 static QSSGRenderGraphObject *updateSpatialNode(QQuick3DObject *o, QSSGRenderGraphObject *n) { return o->updateSpatialNode(n); }
137
138 explicit QQuick3DObjectPrivate(Type t, FlagsT f);
139 explicit QQuick3DObjectPrivate(Type t, Flags f);
140 explicit QQuick3DObjectPrivate(Type t);
141 ~QQuick3DObjectPrivate() override;
142 void init(QQuick3DObject *parent);
143
144 QQmlListProperty<QObject> data();
145 QQmlListProperty<QObject> resources();
146 QQmlListProperty<QQuick3DObject> children();
147
148 QQmlListProperty<QQuickState> states();
149 QQmlListProperty<QQuickTransition> transitions();
150
151 QString state() const;
152 void setState(const QString &);
153
154 // data property
155 static void data_append(QQmlListProperty<QObject> *, QObject *);
156 static qsizetype data_count(QQmlListProperty<QObject> *);
157 static QObject *data_at(QQmlListProperty<QObject> *, qsizetype);
158 static void data_clear(QQmlListProperty<QObject> *);
159
160 // resources property
161 static QObject *resources_at(QQmlListProperty<QObject> *, qsizetype);
162 static void resources_append(QQmlListProperty<QObject> *, QObject *);
163 static qsizetype resources_count(QQmlListProperty<QObject> *);
164 static void resources_clear(QQmlListProperty<QObject> *);
165
166 // children property
167 static void children_append(QQmlListProperty<QQuick3DObject> *, QQuick3DObject *);
168 static qsizetype children_count(QQmlListProperty<QQuick3DObject> *);
169 static QQuick3DObject *children_at(QQmlListProperty<QQuick3DObject> *, qsizetype);
170 static void children_clear(QQmlListProperty<QQuick3DObject> *);
171
172 void _q_resourceObjectDeleted(QObject *);
173 void _q_cleanupContentItem2D();
174 quint64 _q_createJSWrapper(QQmlV4ExecutionEnginePtr engine);
175
176 enum ChangeType {
177 Geometry = 0x01,
178 SiblingOrder = 0x02,
179 Visibility = 0x04,
180 Opacity = 0x08,
181 Destroyed = 0x10,
182 Parent = 0x20,
183 Children = 0x40,
184 Rotation = 0x80,
185 ImplicitWidth = 0x100,
186 ImplicitHeight = 0x200,
187 Enabled = 0x400,
188 };
189
190 Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
191
192 struct ChangeListener
193 {
194 using ChangeTypes = QQuick3DObjectPrivate::ChangeTypes;
195
196 ChangeListener(QQuick3DObjectChangeListener *l = nullptr, ChangeTypes t = {}) : listener(l), types(t) {}
197
198 ChangeListener(QQuick3DObjectChangeListener *l) : listener(l), types(Geometry) {}
199
200 bool operator==(const ChangeListener &other) const
201 {
202 return listener == other.listener && types == other.types;
203 }
204
205 QQuick3DObjectChangeListener *listener;
206 ChangeTypes types;
207 };
208
209 struct ExtraData
210 {
211 ExtraData();
212
213 int hideRefCount;
214 QObjectList resourcesList;
215
216 };
217 QLazilyAllocated<ExtraData> extra;
218
219 QVector<QQuick3DObjectPrivate::ChangeListener> changeListeners;
220
221 void addItemChangeListener(QQuick3DObjectChangeListener *listener, ChangeTypes types);
222 void updateOrAddItemChangeListener(QQuick3DObjectChangeListener *listener, ChangeTypes types);
223 void removeItemChangeListener(QQuick3DObjectChangeListener *, ChangeTypes types);
224
225 QQuickStateGroup *_states();
226 QQuickStateGroup *_stateGroup;
227
228 enum DirtyType {
229 TransformOrigin = 0x00000001,
230 Transform = 0x00000002,
231 BasicTransform = 0x00000004,
232 Position = 0x00000008,
233 Size = 0x00000010,
234
235 ZValue = 0x00000020,
236 Content = 0x00000040,
237 Smooth = 0x00000080,
238 OpacityValue = 0x00000100,
239 ChildrenChanged = 0x00000200,
240 ChildrenStackingChanged = 0x00000400,
241 ParentChanged = 0x00000800,
242
243 Clip = 0x00001000,
244 Window = 0x00002000,
245
246 EffectReference = 0x00008000,
247 Visible = 0x00010000,
248 HideReference = 0x00020000,
249 Antialiasing = 0x00040000,
250
251 InstanceRootChanged = 0x00080000,
252 // When you add an attribute here, don't forget to update
253 // dirtyToString()
254
255 TransformUpdateMask = TransformOrigin | Transform | BasicTransform | Position | Window,
256 ComplexTransformUpdateMask = Transform | Window,
257 ContentUpdateMask = Size | Content | Smooth | Window | Antialiasing,
258 ChildrenUpdateMask = ChildrenChanged | ChildrenStackingChanged | EffectReference | Window
259 };
260
261 quint32 dirtyAttributes;
262 QString dirtyToString() const;
263 void dirty(DirtyType);
264 void addToDirtyList();
265 void removeFromDirtyList();
266 QQuick3DObject *nextDirtyItem;
267 QQuick3DObject **prevDirtyItem;
268
269 bool hasFlag(Flags flag) { return (flags & FlagsT(flag)) != 0; }
270
271 void setCulled(bool);
272
273 QPointer<QQuick3DSceneManager> sceneManager;
274 int sceneRefCount;
275
276 QQuick3DObject *parentItem;
277
278 QList<QQuick3DObject *> childItems;
279 void addChild(QQuick3DObject *);
280 void removeChild(QQuick3DObject *);
281 void siblingOrderChanged();
282
283 void refSceneManager(QQuick3DSceneManager &);
284 void derefSceneManager();
285
286 static void refSceneManager(QQuick3DObject *obj, QQuick3DSceneManager &mgr)
287 {
288 if (obj)
289 QQuick3DObjectPrivate::get(obj)->refSceneManager(mgr);
290 }
291 static void derefSceneManager(QQuick3DObject *obj)
292 {
293 if (obj)
294 QQuick3DObjectPrivate::get(obj)->derefSceneManager();
295 }
296
297 QQuick3DObject *subFocusItem;
298 void updateSubFocusItem(QQuick3DObject *scope, bool focus);
299
300 void itemChange(QQuick3DObject::ItemChange, const QQuick3DObject::ItemChangeData &);
301
302 virtual void updatePolish() {}
303
304 void requestSecondaryUpdate() { secondaryUpdateRequested = true; }
305
306 QSSGRenderGraphObject *spatialNode = nullptr;
307
308 Type type = Type::Unknown;
309 FlagsT flags = FlagsT(Flags::None);
310 bool secondaryUpdateRequested = false;
311 bool componentComplete = true;
312 bool preSyncNeeded = false;
313 bool culled;
314 bool sharedResource = false;
315 QQuick3DItem2D *contentItem2d = nullptr;
316 ConnectionMap connectionMap;
317 Q_QUICK3D_PROFILE_ID
318};
319
320Q_DECLARE_OPERATORS_FOR_FLAGS(QQuick3DObjectPrivate::ChangeTypes)
321Q_DECLARE_TYPEINFO(QQuick3DObjectPrivate::ChangeListener, Q_PRIMITIVE_TYPE);
323
324inline size_t qHash(const QQuick3DObjectPrivate::ConnectionKey &con, size_t seed = 0) noexcept
325{
326 return qHashBits(&con, sizeof(QQuick3DObjectPrivate::ConnectionKey), seed);
327}
328
329QT_END_NAMESPACE
330
331#endif // QSSGOBJECT_P_H
Combined button and popup list for selecting options.
Q_DECLARE_TYPEINFO(QDateTime::Data, Q_RELOCATABLE_TYPE)
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept
Definition qsize.h:192