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