1 | // Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qscene_p.h" |
5 | |
6 | #include <Qt3DCore/qnode.h> |
7 | #include <QtCore/QHash> |
8 | #include <QtCore/QReadLocker> |
9 | |
10 | #include <Qt3DCore/private/qnode_p.h> |
11 | #include <Qt3DCore/qaspectengine.h> |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | namespace Qt3DCore { |
16 | |
17 | class QScenePrivate |
18 | { |
19 | public: |
20 | QScenePrivate(QAspectEngine *engine) |
21 | : m_engine(engine) |
22 | , m_arbiter(nullptr) |
23 | //m_postConstructorInit needs the parent set correctly for QObject::moveToThread() to work correctly |
24 | , m_postConstructorInit(new NodePostConstructorInit(engine)) |
25 | , m_rootNode(nullptr) |
26 | { |
27 | } |
28 | |
29 | QAspectEngine *m_engine; |
30 | QHash<QNodeId, QNode *> m_nodeLookupTable; |
31 | QMultiHash<QNodeId, QNodeId> m_componentToEntities; |
32 | QChangeArbiter *m_arbiter; |
33 | QScopedPointer<NodePostConstructorInit, QScopedPointerDeleteLater> m_postConstructorInit; |
34 | mutable QReadWriteLock m_lock; |
35 | mutable QReadWriteLock m_nodePropertyTrackModeLock; |
36 | QNode *m_rootNode; |
37 | QScene::DirtyNodeSet m_dirtyBits; |
38 | }; |
39 | |
40 | |
41 | QScene::QScene(QAspectEngine *engine) |
42 | : d_ptr(new QScenePrivate(engine)) |
43 | { |
44 | } |
45 | |
46 | QScene::~QScene() |
47 | { |
48 | } |
49 | |
50 | QAspectEngine *QScene::engine() const |
51 | { |
52 | Q_D(const QScene); |
53 | return d->m_engine; |
54 | } |
55 | |
56 | // Called by main thread only |
57 | void QScene::addObservable(QNode *observable) |
58 | { |
59 | Q_D(QScene); |
60 | if (observable != nullptr) { |
61 | QWriteLocker lock(&d->m_lock); |
62 | d->m_nodeLookupTable.insert(key: observable->id(), value: observable); |
63 | if (d->m_arbiter != nullptr) |
64 | observable->d_func()->setArbiter(d->m_arbiter); |
65 | } |
66 | } |
67 | |
68 | // Called by main thread |
69 | void QScene::removeObservable(QNode *observable) |
70 | { |
71 | Q_D(QScene); |
72 | if (observable != nullptr) { |
73 | QWriteLocker lock(&d->m_lock); |
74 | const QNodeId nodeUuid = observable->id(); |
75 | d->m_nodeLookupTable.remove(key: nodeUuid); |
76 | observable->d_func()->setArbiter(nullptr); |
77 | } |
78 | } |
79 | |
80 | // Called by any thread |
81 | QNode *QScene::lookupNode(QNodeId id) const |
82 | { |
83 | Q_D(const QScene); |
84 | QReadLocker lock(&d->m_lock); |
85 | return d->m_nodeLookupTable.value(key: id); |
86 | } |
87 | |
88 | QList<QNode *> QScene::lookupNodes(const QList<QNodeId> &ids) const |
89 | { |
90 | Q_D(const QScene); |
91 | QReadLocker lock(&d->m_lock); |
92 | QList<QNode *> nodes; |
93 | nodes.reserve(asize: ids.size()); |
94 | for (QNodeId id : ids) |
95 | nodes.push_back(t: d->m_nodeLookupTable.value(key: id)); |
96 | return nodes; |
97 | } |
98 | |
99 | QNode *QScene::rootNode() const |
100 | { |
101 | Q_D(const QScene); |
102 | return d->m_rootNode; |
103 | } |
104 | |
105 | void QScene::setArbiter(QChangeArbiter *arbiter) |
106 | { |
107 | Q_D(QScene); |
108 | d->m_arbiter = arbiter; |
109 | } |
110 | |
111 | QChangeArbiter *QScene::arbiter() const |
112 | { |
113 | Q_D(const QScene); |
114 | return d->m_arbiter; |
115 | } |
116 | |
117 | QList<QNodeId> QScene::entitiesForComponent(QNodeId id) const |
118 | { |
119 | Q_D(const QScene); |
120 | QReadLocker lock(&d->m_lock); |
121 | QList<QNodeId> result; |
122 | const auto p = d->m_componentToEntities.equal_range(key: id); |
123 | for (auto it = p.first; it != p.second; ++it) |
124 | result.push_back(t: *it); |
125 | return result; |
126 | } |
127 | |
128 | void QScene::addEntityForComponent(QNodeId componentUuid, QNodeId entityUuid) |
129 | { |
130 | Q_D(QScene); |
131 | QWriteLocker lock(&d->m_lock); |
132 | d->m_componentToEntities.insert(key: componentUuid, value: entityUuid); |
133 | } |
134 | |
135 | void QScene::removeEntityForComponent(QNodeId componentUuid, QNodeId entityUuid) |
136 | { |
137 | Q_D(QScene); |
138 | QWriteLocker lock(&d->m_lock); |
139 | d->m_componentToEntities.remove(key: componentUuid, value: entityUuid); |
140 | } |
141 | |
142 | bool QScene::hasEntityForComponent(QNodeId componentUuid, QNodeId entityUuid) |
143 | { |
144 | Q_D(QScene); |
145 | QReadLocker lock(&d->m_lock); |
146 | const auto range = d->m_componentToEntities.equal_range(key: componentUuid); |
147 | return std::find(first: range.first, last: range.second, val: entityUuid) != range.second; |
148 | } |
149 | |
150 | NodePostConstructorInit *QScene::postConstructorInit() const |
151 | { |
152 | Q_D(const QScene); |
153 | return d->m_postConstructorInit.get(); |
154 | } |
155 | |
156 | QScene::DirtyNodeSet QScene::dirtyBits() |
157 | { |
158 | Q_D(QScene); |
159 | return d->m_dirtyBits; |
160 | } |
161 | |
162 | void QScene::clearDirtyBits() |
163 | { |
164 | Q_D(QScene); |
165 | d->m_dirtyBits = {}; |
166 | } |
167 | |
168 | void QScene::markDirty(QScene::DirtyNodeSet changes) |
169 | { |
170 | Q_D(QScene); |
171 | d->m_dirtyBits |= changes; |
172 | } |
173 | |
174 | void QScene::setRootNode(QNode *root) |
175 | { |
176 | Q_D(QScene); |
177 | d->m_rootNode = root; |
178 | } |
179 | |
180 | } // Qt3D |
181 | |
182 | QT_END_NAMESPACE |
183 | |