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
50QT_BEGIN_NAMESPACE
51
52namespace Qt3DCore {
53
54class QScenePrivate
55{
56public:
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 QLockableObserverInterface *m_arbiter;
72 QScopedPointer<NodePostConstructorInit> m_postConstructorInit;
73 mutable QReadWriteLock m_lock;
74 mutable QReadWriteLock m_nodePropertyTrackModeLock;
75 QNode *m_rootNode;
76};
77
78
79QScene::QScene(QAspectEngine *engine)
80 : d_ptr(new QScenePrivate(engine))
81{
82}
83
84QScene::~QScene()
85{
86}
87
88QAspectEngine *QScene::engine() const
89{
90 Q_D(const QScene);
91 return d->m_engine;
92}
93
94// Called by any thread
95void QScene::addObservable(QObservableInterface *observable, QNodeId id)
96{
97 Q_D(QScene);
98 QWriteLocker lock(&d->m_lock);
99 d->m_observablesLookupTable.insert(id, observable);
100 d->m_observableToUuid.insert(observable, id);
101 if (d->m_arbiter != nullptr)
102 observable->setArbiter(d->m_arbiter);
103}
104
105// Called by main thread only
106void QScene::addObservable(QNode *observable)
107{
108 Q_D(QScene);
109 if (observable != nullptr) {
110 QWriteLocker lock(&d->m_lock);
111 d->m_nodeLookupTable.insert(observable->id(), observable);
112 if (d->m_arbiter != nullptr)
113 observable->d_func()->setArbiter(d->m_arbiter);
114 }
115}
116
117// Called by any thread
118void QScene::removeObservable(QObservableInterface *observable, QNodeId id)
119{
120 Q_D(QScene);
121 QWriteLocker lock(&d->m_lock);
122 d->m_observablesLookupTable.remove(id, observable);
123 d->m_observableToUuid.remove(observable);
124 observable->setArbiter(nullptr);
125}
126
127// Called by main thread
128void 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(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(it.value());
139 it = d->m_observablesLookupTable.erase(it);
140 }
141 d->m_nodeLookupTable.remove(nodeUuid);
142 observable->d_func()->setArbiter(nullptr);
143 }
144}
145
146// Called by any thread
147QObservableList QScene::lookupObservables(QNodeId id) const
148{
149 Q_D(const QScene);
150 QReadLocker lock(&d->m_lock);
151 return d->m_observablesLookupTable.values(id);
152}
153
154// Called by any thread
155QNode *QScene::lookupNode(QNodeId id) const
156{
157 Q_D(const QScene);
158 QReadLocker lock(&d->m_lock);
159 return d->m_nodeLookupTable.value(id);
160}
161
162QVector<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(id);
170 return nodes;
171}
172
173QNodeId QScene::nodeIdFromObservable(QObservableInterface *observable) const
174{
175 Q_D(const QScene);
176 QReadLocker lock(&d->m_lock);
177 return d->m_observableToUuid.value(observable);
178}
179
180QNode *QScene::rootNode() const
181{
182 Q_D(const QScene);
183 return d->m_rootNode;
184}
185
186void QScene::setArbiter(QLockableObserverInterface *arbiter)
187{
188 Q_D(QScene);
189 d->m_arbiter = arbiter;
190}
191
192QLockableObserverInterface *QScene::arbiter() const
193{
194 Q_D(const QScene);
195 return d->m_arbiter;
196}
197
198QVector<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(id);
204 for (auto it = p.first; it != p.second; ++it)
205 result.push_back(*it);
206 return result;
207}
208
209void QScene::addEntityForComponent(QNodeId componentUuid, QNodeId entityUuid)
210{
211 Q_D(QScene);
212 QWriteLocker lock(&d->m_lock);
213 d->m_componentToEntities.insert(componentUuid, entityUuid);
214}
215
216void QScene::removeEntityForComponent(QNodeId componentUuid, QNodeId entityUuid)
217{
218 Q_D(QScene);
219 QWriteLocker lock(&d->m_lock);
220 d->m_componentToEntities.remove(componentUuid, entityUuid);
221}
222
223bool 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(componentUuid);
228 return std::find(range.first, range.second, entityUuid) != range.second;
229}
230
231QScene::NodePropertyTrackData QScene::lookupNodePropertyTrackData(QNodeId id) const
232{
233 Q_D(const QScene);
234 QReadLocker lock(&d->m_nodePropertyTrackModeLock);
235 return d->m_nodePropertyTrackModeLookupTable.value(id);
236}
237
238void QScene::setPropertyTrackDataForNode(QNodeId nodeId, const QScene::NodePropertyTrackData &data)
239{
240 Q_D(QScene);
241 QWriteLocker lock(&d->m_nodePropertyTrackModeLock);
242 d->m_nodePropertyTrackModeLookupTable.insert(nodeId, data);
243}
244
245void QScene::removePropertyTrackDataForNode(QNodeId nodeId)
246{
247 Q_D(QScene);
248 QWriteLocker lock(&d->m_nodePropertyTrackModeLock);
249 d->m_nodePropertyTrackModeLookupTable.remove(nodeId);
250}
251
252NodePostConstructorInit *QScene::postConstructorInit() const
253{
254 Q_D(const QScene);
255 return d->m_postConstructorInit.get();
256}
257
258void QScene::setRootNode(QNode *root)
259{
260 Q_D(QScene);
261 d->m_rootNode = root;
262}
263
264} // Qt3D
265
266QT_END_NAMESPACE
267