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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtquick3d/src/quick3d/qquick3dobject_p.h