1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt3D module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qscene_p.h" |
41 | |
42 | #include <Qt3DCore/qnode.h> |
43 | #include <QtCore/QHash> |
44 | #include <QtCore/QReadLocker> |
45 | |
46 | #include <Qt3DCore/private/qlockableobserverinterface_p.h> |
47 | #include <Qt3DCore/private/qnode_p.h> |
48 | #include <Qt3DCore/private/qobservableinterface_p.h> |
49 | |
50 | QT_BEGIN_NAMESPACE |
51 | |
52 | namespace Qt3DCore { |
53 | |
54 | class QScenePrivate |
55 | { |
56 | public: |
57 | QScenePrivate(QAspectEngine *engine) |
58 | : m_engine(engine) |
59 | , m_arbiter(nullptr) |
60 | , m_postConstructorInit(new NodePostConstructorInit) |
61 | , m_rootNode(nullptr) |
62 | { |
63 | } |
64 | |
65 | QAspectEngine *m_engine; |
66 | QHash<QNodeId, QNode *> m_nodeLookupTable; |
67 | QMultiHash<QNodeId, QNodeId> m_componentToEntities; |
68 | QMultiHash<QNodeId, QObservableInterface *> m_observablesLookupTable; |
69 | QHash<QObservableInterface *, QNodeId> m_observableToUuid; |
70 | QHash<QNodeId, QScene::NodePropertyTrackData> m_nodePropertyTrackModeLookupTable; |
71 | QAbstractArbiter *m_arbiter; |
72 | QScopedPointer<NodePostConstructorInit> m_postConstructorInit; |
73 | mutable QReadWriteLock m_lock; |
74 | mutable QReadWriteLock m_nodePropertyTrackModeLock; |
75 | QNode *m_rootNode; |
76 | }; |
77 | |
78 | |
79 | QScene::QScene(QAspectEngine *engine) |
80 | : d_ptr(new QScenePrivate(engine)) |
81 | { |
82 | } |
83 | |
84 | QScene::~QScene() |
85 | { |
86 | } |
87 | |
88 | QAspectEngine *QScene::engine() const |
89 | { |
90 | Q_D(const QScene); |
91 | return d->m_engine; |
92 | } |
93 | |
94 | // Called by any thread |
95 | void QScene::addObservable(QObservableInterface *observable, QNodeId id) |
96 | { |
97 | Q_D(QScene); |
98 | QWriteLocker lock(&d->m_lock); |
99 | d->m_observablesLookupTable.insert(akey: id, avalue: observable); |
100 | d->m_observableToUuid.insert(akey: observable, avalue: id); |
101 | if (d->m_arbiter != nullptr) |
102 | observable->setArbiter(d->m_arbiter); |
103 | } |
104 | |
105 | // Called by main thread only |
106 | void QScene::addObservable(QNode *observable) |
107 | { |
108 | Q_D(QScene); |
109 | if (observable != nullptr) { |
110 | QWriteLocker lock(&d->m_lock); |
111 | d->m_nodeLookupTable.insert(akey: observable->id(), avalue: observable); |
112 | if (d->m_arbiter != nullptr) |
113 | observable->d_func()->setArbiter(d->m_arbiter); |
114 | } |
115 | } |
116 | |
117 | // Called by any thread |
118 | void QScene::removeObservable(QObservableInterface *observable, QNodeId id) |
119 | { |
120 | Q_D(QScene); |
121 | QWriteLocker lock(&d->m_lock); |
122 | d->m_observablesLookupTable.remove(key: id, value: observable); |
123 | d->m_observableToUuid.remove(akey: observable); |
124 | observable->setArbiter(nullptr); |
125 | } |
126 | |
127 | // Called by main thread |
128 | void QScene::removeObservable(QNode *observable) |
129 | { |
130 | Q_D(QScene); |
131 | if (observable != nullptr) { |
132 | QWriteLocker lock(&d->m_lock); |
133 | QNodeId nodeUuid = observable->id(); |
134 | const auto p = d->m_observablesLookupTable.equal_range(akey: nodeUuid); // must be non-const equal_range to ensure p.second stays valid |
135 | auto it = p.first; |
136 | while (it != p.second) { |
137 | it.value()->setArbiter(nullptr); |
138 | d->m_observableToUuid.remove(akey: it.value()); |
139 | it = d->m_observablesLookupTable.erase(it); |
140 | } |
141 | d->m_nodeLookupTable.remove(akey: nodeUuid); |
142 | observable->d_func()->setArbiter(nullptr); |
143 | } |
144 | } |
145 | |
146 | // Called by any thread |
147 | QObservableList QScene::lookupObservables(QNodeId id) const |
148 | { |
149 | Q_D(const QScene); |
150 | QReadLocker lock(&d->m_lock); |
151 | return d->m_observablesLookupTable.values(akey: id); |
152 | } |
153 | |
154 | // Called by any thread |
155 | QNode *QScene::lookupNode(QNodeId id) const |
156 | { |
157 | Q_D(const QScene); |
158 | QReadLocker lock(&d->m_lock); |
159 | return d->m_nodeLookupTable.value(akey: id); |
160 | } |
161 | |
162 | QVector<QNode *> QScene::lookupNodes(const QVector<QNodeId> &ids) const |
163 | { |
164 | Q_D(const QScene); |
165 | QReadLocker lock(&d->m_lock); |
166 | QVector<QNode *> nodes(ids.size()); |
167 | int index = 0; |
168 | for (QNodeId id : ids) |
169 | nodes[index++] = d->m_nodeLookupTable.value(akey: id); |
170 | return nodes; |
171 | } |
172 | |
173 | QNodeId QScene::nodeIdFromObservable(QObservableInterface *observable) const |
174 | { |
175 | Q_D(const QScene); |
176 | QReadLocker lock(&d->m_lock); |
177 | return d->m_observableToUuid.value(akey: observable); |
178 | } |
179 | |
180 | QNode *QScene::rootNode() const |
181 | { |
182 | Q_D(const QScene); |
183 | return d->m_rootNode; |
184 | } |
185 | |
186 | void QScene::setArbiter(QAbstractArbiter *arbiter) |
187 | { |
188 | Q_D(QScene); |
189 | d->m_arbiter = arbiter; |
190 | } |
191 | |
192 | QAbstractArbiter *QScene::arbiter() const |
193 | { |
194 | Q_D(const QScene); |
195 | return d->m_arbiter; |
196 | } |
197 | |
198 | QVector<QNodeId> QScene::entitiesForComponent(QNodeId id) const |
199 | { |
200 | Q_D(const QScene); |
201 | QReadLocker lock(&d->m_lock); |
202 | QVector<QNodeId> result; |
203 | const auto p = d->m_componentToEntities.equal_range(akey: id); |
204 | for (auto it = p.first; it != p.second; ++it) |
205 | result.push_back(t: *it); |
206 | return result; |
207 | } |
208 | |
209 | void QScene::addEntityForComponent(QNodeId componentUuid, QNodeId entityUuid) |
210 | { |
211 | Q_D(QScene); |
212 | QWriteLocker lock(&d->m_lock); |
213 | d->m_componentToEntities.insert(akey: componentUuid, avalue: entityUuid); |
214 | } |
215 | |
216 | void QScene::removeEntityForComponent(QNodeId componentUuid, QNodeId entityUuid) |
217 | { |
218 | Q_D(QScene); |
219 | QWriteLocker lock(&d->m_lock); |
220 | d->m_componentToEntities.remove(key: componentUuid, value: entityUuid); |
221 | } |
222 | |
223 | bool QScene::hasEntityForComponent(QNodeId componentUuid, QNodeId entityUuid) |
224 | { |
225 | Q_D(QScene); |
226 | QReadLocker lock(&d->m_lock); |
227 | const auto range = d->m_componentToEntities.equal_range(akey: componentUuid); |
228 | return std::find(first: range.first, last: range.second, val: entityUuid) != range.second; |
229 | } |
230 | |
231 | QScene::NodePropertyTrackData QScene::lookupNodePropertyTrackData(QNodeId id) const |
232 | { |
233 | Q_D(const QScene); |
234 | QReadLocker lock(&d->m_nodePropertyTrackModeLock); |
235 | return d->m_nodePropertyTrackModeLookupTable.value(akey: id); |
236 | } |
237 | |
238 | void QScene::setPropertyTrackDataForNode(QNodeId nodeId, const QScene::NodePropertyTrackData &data) |
239 | { |
240 | Q_D(QScene); |
241 | QWriteLocker lock(&d->m_nodePropertyTrackModeLock); |
242 | d->m_nodePropertyTrackModeLookupTable.insert(akey: nodeId, avalue: data); |
243 | } |
244 | |
245 | void QScene::removePropertyTrackDataForNode(QNodeId nodeId) |
246 | { |
247 | Q_D(QScene); |
248 | QWriteLocker lock(&d->m_nodePropertyTrackModeLock); |
249 | d->m_nodePropertyTrackModeLookupTable.remove(akey: nodeId); |
250 | } |
251 | |
252 | NodePostConstructorInit *QScene::postConstructorInit() const |
253 | { |
254 | Q_D(const QScene); |
255 | return d->m_postConstructorInit.get(); |
256 | } |
257 | |
258 | void QScene::setRootNode(QNode *root) |
259 | { |
260 | Q_D(QScene); |
261 | d->m_rootNode = root; |
262 | } |
263 | |
264 | } // Qt3D |
265 | |
266 | QT_END_NAMESPACE |
267 | |