| 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 "qentity.h" | 
| 41 | #include "qentity_p.h" | 
| 42 |  | 
| 43 | #include <Qt3DCore/qcomponent.h> | 
| 44 | #include <Qt3DCore/qnodecreatedchange.h> | 
| 45 | #include <QtCore/QMetaObject> | 
| 46 | #include <QtCore/QMetaProperty> | 
| 47 |  | 
| 48 | #include <Qt3DCore/private/corelogging_p.h> | 
| 49 | #include <Qt3DCore/private/qcomponent_p.h> | 
| 50 | #include <Qt3DCore/private/qscene_p.h> | 
| 51 |  | 
| 52 | #include <QQueue> | 
| 53 |  | 
| 54 | QT_BEGIN_NAMESPACE | 
| 55 |  | 
| 56 | namespace { | 
| 57 |  | 
| 58 | QString dumpNode(const Qt3DCore::QEntity *n) { | 
| 59 |     auto formatNode = [](const Qt3DCore::QNode *n) { | 
| 60 |         QString res = QString(QLatin1String("%1{%2}" )) | 
| 61 |                           .arg(a: QLatin1String(n->metaObject()->className())) | 
| 62 |                           .arg(a: n->id().id()); | 
| 63 |         if (!n->objectName().isEmpty()) | 
| 64 |             res += QString(QLatin1String(" (%1)" )).arg(a: n->objectName()); | 
| 65 |         if (!n->isEnabled()) | 
| 66 |             res += QLatin1String(" [D]" ); | 
| 67 |         return res; | 
| 68 |     }; | 
| 69 |  | 
| 70 |     QString res = formatNode(n); | 
| 71 |     const auto &components = n->components(); | 
| 72 |     if (components.size()) { | 
| 73 |         QStringList componentNames; | 
| 74 |         for (const auto &c : components) | 
| 75 |             componentNames += formatNode(c); | 
| 76 |         res += QString(QLatin1String(" [ %1 ]" )).arg(a: componentNames.join(sep: QLatin1String(", " ))); | 
| 77 |     } | 
| 78 |  | 
| 79 |     return res; | 
| 80 | } | 
| 81 |  | 
| 82 | QStringList dumpSG(const Qt3DCore::QNode *n, int level = 0) | 
| 83 | { | 
| 84 |     QStringList reply; | 
| 85 |     const auto *entity = qobject_cast<const Qt3DCore::QEntity *>(object: n); | 
| 86 |     if (entity != nullptr) { | 
| 87 |         QString res = dumpNode(n: entity); | 
| 88 |         reply += res.rightJustified(width: res.length() + level * 2, fill: ' '); | 
| 89 |         level++; | 
| 90 |     } | 
| 91 |  | 
| 92 |     const auto children = n->childNodes(); | 
| 93 |     for (auto *child: children) | 
| 94 |         reply += dumpSG(n: child, level); | 
| 95 |  | 
| 96 |     return reply; | 
| 97 | } | 
| 98 |  | 
| 99 | } | 
| 100 |  | 
| 101 | namespace Qt3DCore { | 
| 102 |  | 
| 103 | /*! | 
| 104 |     \class Qt3DCore::QEntity | 
| 105 |     \inmodule Qt3DCore | 
| 106 |     \inherits Qt3DCore::QNode | 
| 107 |     \since 5.5 | 
| 108 |  | 
| 109 |     \brief Qt3DCore::QEntity is a Qt3DCore::QNode subclass that can aggregate several | 
| 110 |     Qt3DCore::QComponent instances that will specify its behavior. | 
| 111 |  | 
| 112 |     By itself a Qt3DCore::QEntity is an empty shell. The behavior of a Qt3DCore::QEntity | 
| 113 |     object is defined by the Qt3DCore::QComponent objects it references. Each Qt3D | 
| 114 |     backend aspect will be able to interpret and process an Entity by | 
| 115 |     recognizing which components it is made up of. One aspect may decide to only | 
| 116 |     process entities composed of a single Qt3DCore::QTransform component whilst | 
| 117 |     another may focus on Qt3DInput::QMouseHandler. | 
| 118 |  | 
| 119 |     \sa Qt3DCore::QComponent, Qt3DCore::QTransform | 
| 120 |  */ | 
| 121 |  | 
| 122 | /*! | 
| 123 |     \fn template<typename T> QVector<T *> Qt3DCore::QEntity::componentsOfType() const | 
| 124 |  | 
| 125 |     Returns all the components added to this entity that can be cast to | 
| 126 |     type T or an empty vector if there are no such components. | 
| 127 | */ | 
| 128 |  | 
| 129 | /*! \internal */ | 
| 130 | QEntityPrivate::QEntityPrivate() | 
| 131 |     : QNodePrivate() | 
| 132 |     , m_parentEntityId() | 
| 133 | {} | 
| 134 |  | 
| 135 | /*! \internal */ | 
| 136 | QEntityPrivate::~QEntityPrivate() | 
| 137 | { | 
| 138 | } | 
| 139 |  | 
| 140 | /*! \internal */ | 
| 141 | void QEntityPrivate::removeDestroyedComponent(QComponent *comp) | 
| 142 | { | 
| 143 |     // comp is actually no longer a QComponent, just a QObject | 
| 144 |  | 
| 145 |     Q_CHECK_PTR(comp); | 
| 146 |     qCDebug(Nodes) << Q_FUNC_INFO << comp; | 
| 147 |  | 
| 148 |     updateNode(node: comp, property: nullptr, change: ComponentRemoved); | 
| 149 |     m_components.removeOne(t: comp); | 
| 150 |  | 
| 151 |     // Remove bookkeeping connection | 
| 152 |     unregisterDestructionHelper(node: comp); | 
| 153 | } | 
| 154 |  | 
| 155 | /*! | 
| 156 |     Constructs a new Qt3DCore::QEntity instance with \a parent as parent. | 
| 157 |  */ | 
| 158 | QEntity::QEntity(QNode *parent) | 
| 159 |     : QEntity(*new QEntityPrivate, parent) {} | 
| 160 |  | 
| 161 | /*! \internal */ | 
| 162 | QEntity::QEntity(QEntityPrivate &dd, QNode *parent) | 
| 163 |     : QNode(dd, parent) | 
| 164 | { | 
| 165 |     connect(sender: this, signal: &QNode::parentChanged, receiver: this, slot: &QEntity::onParentChanged); | 
| 166 | } | 
| 167 |  | 
| 168 | QEntity::~QEntity() | 
| 169 | { | 
| 170 |     // remove all component aggregations | 
| 171 |     Q_D(const QEntity); | 
| 172 |     // to avoid hammering m_components by repeated removeComponent() | 
| 173 |     // calls below, move all contents out, so the removeOne() calls in | 
| 174 |     // removeComponent() don't actually remove something: | 
| 175 |     const auto components = std::move(d->m_components); | 
| 176 |     for (QComponent *comp : components) | 
| 177 |         removeComponent(comp); | 
| 178 | } | 
| 179 |  | 
| 180 |  | 
| 181 | /*! | 
| 182 |     \typedef Qt3DCore::QComponentVector | 
| 183 |     \relates Qt3DCore::QEntity | 
| 184 |  | 
| 185 |     List of QComponent pointers. | 
| 186 |  */ | 
| 187 |  | 
| 188 | /*! | 
| 189 |     Returns the list of Qt3DCore::QComponent instances the entity is referencing. | 
| 190 |  */ | 
| 191 | QComponentVector QEntity::components() const | 
| 192 | { | 
| 193 |     Q_D(const QEntity); | 
| 194 |     return d->m_components; | 
| 195 | } | 
| 196 |  | 
| 197 | /*! | 
| 198 |     Adds a new reference to the component \a comp. | 
| 199 |  | 
| 200 |     \note If the Qt3DCore::QComponent has no parent, the Qt3DCore::QEntity will set | 
| 201 |     itself as its parent thereby taking ownership of the component. | 
| 202 |  */ | 
| 203 | void QEntity::addComponent(QComponent *comp) | 
| 204 | { | 
| 205 |     Q_D(QEntity); | 
| 206 |     Q_CHECK_PTR( comp ); | 
| 207 |     qCDebug(Nodes) << Q_FUNC_INFO << comp; | 
| 208 |  | 
| 209 |     // A Component can only be aggregated once | 
| 210 |     if (d->m_components.count(t: comp) != 0) | 
| 211 |         return ; | 
| 212 |  | 
| 213 |     // We need to add it as a child of the current node if it has been declared inline | 
| 214 |     // Or not previously added as a child of the current node so that | 
| 215 |     // 1) The backend gets notified about it's creation | 
| 216 |     // 2) When the current node is destroyed, it gets destroyed as well | 
| 217 |     if (!comp->parent()) | 
| 218 |         comp->setParent(this); | 
| 219 |  | 
| 220 |     QNodePrivate::get(q: comp)->_q_ensureBackendNodeCreated(); | 
| 221 |  | 
| 222 |     d->m_components.append(t: comp); | 
| 223 |  | 
| 224 |     // Ensures proper bookkeeping | 
| 225 |     d->registerPrivateDestructionHelper(node: comp, func: &QEntityPrivate::removeDestroyedComponent); | 
| 226 |  | 
| 227 |     d->updateNode(node: comp, property: nullptr, change: ComponentAdded); | 
| 228 |     static_cast<QComponentPrivate *>(QComponentPrivate::get(q: comp))->addEntity(entity: this); | 
| 229 | } | 
| 230 |  | 
| 231 | /*! | 
| 232 |     Removes the reference to \a comp. | 
| 233 |  */ | 
| 234 | void QEntity::removeComponent(QComponent *comp) | 
| 235 | { | 
| 236 |     Q_CHECK_PTR(comp); | 
| 237 |     qCDebug(Nodes) << Q_FUNC_INFO << comp; | 
| 238 |     Q_D(QEntity); | 
| 239 |  | 
| 240 |     static_cast<QComponentPrivate *>(QComponentPrivate::get(q: comp))->removeEntity(entity: this); | 
| 241 |  | 
| 242 |     d->updateNode(node: comp, property: nullptr, change: ComponentRemoved); | 
| 243 |  | 
| 244 |     d->m_components.removeOne(t: comp); | 
| 245 |  | 
| 246 |     // Remove bookkeeping connection | 
| 247 |     d->unregisterDestructionHelper(node: comp); | 
| 248 | } | 
| 249 |  | 
| 250 | /*! | 
| 251 |     Returns the parent Qt3DCore::QEntity instance of this entity. If the | 
| 252 |     immediate parent isn't a Qt3DCore::QEntity, this function traverses up the | 
| 253 |     scene hierarchy until a parent Qt3DCore::QEntity is found. If no | 
| 254 |     Qt3DCore::QEntity parent can be found, returns null. | 
| 255 |  */ | 
| 256 | QEntity *QEntity::parentEntity() const | 
| 257 | { | 
| 258 |     Q_D(const QEntity); | 
| 259 |     QNode *parentNode = QNode::parentNode(); | 
| 260 |     QEntity *parentEntity = qobject_cast<QEntity *>(object: parentNode); | 
| 261 |  | 
| 262 |     while (parentEntity == nullptr && parentNode != nullptr) { | 
| 263 |         parentNode = parentNode->parentNode(); | 
| 264 |         parentEntity = qobject_cast<QEntity*>(object: parentNode); | 
| 265 |     } | 
| 266 |     if (!parentEntity) { | 
| 267 |         if (!d->m_parentEntityId.isNull()) | 
| 268 |             d->m_parentEntityId = QNodeId(); | 
| 269 |     } else { | 
| 270 |         if (d->m_parentEntityId != parentEntity->id()) | 
| 271 |             d->m_parentEntityId = parentEntity->id(); | 
| 272 |     } | 
| 273 |     return parentEntity; | 
| 274 | } | 
| 275 |  | 
| 276 | /* | 
| 277 |     \internal | 
| 278 |  | 
| 279 |     Returns the Qt3DCore::QNodeId id of the parent Qt3DCore::QEntity instance of the | 
| 280 |     current Qt3DCore::QEntity object. The QNodeId isNull method will return true if | 
| 281 |     there is no Qt3DCore::QEntity parent of the current Qt3DCore::QEntity in the scene | 
| 282 |     hierarchy. | 
| 283 |  */ | 
| 284 | QNodeId QEntityPrivate::parentEntityId() const | 
| 285 | { | 
| 286 |     Q_Q(const QEntity); | 
| 287 |     if (m_parentEntityId.isNull()) | 
| 288 |         q->parentEntity(); | 
| 289 |     return m_parentEntityId; | 
| 290 | } | 
| 291 |  | 
| 292 | QString QEntityPrivate::dumpSceneGraph() const | 
| 293 | { | 
| 294 |     Q_Q(const QEntity); | 
| 295 |     return dumpSG(n: q).join(sep: '\n'); | 
| 296 | } | 
| 297 |  | 
| 298 | QNodeCreatedChangeBasePtr QEntity::createNodeCreationChange() const | 
| 299 | { | 
| 300 |     auto creationChange = QNodeCreatedChangePtr<QEntityData>::create(arguments: this); | 
| 301 |     auto &data = creationChange->data; | 
| 302 |  | 
| 303 |     Q_D(const QEntity); | 
| 304 |     data.parentEntityId = parentEntity() ? parentEntity()->id() : Qt3DCore::QNodeId(); | 
| 305 |  | 
| 306 |     // Find all child entities | 
| 307 |     QQueue<QNode *> queue; | 
| 308 |     queue.append(t: childNodes().toList()); | 
| 309 |     data.childEntityIds.reserve(asize: queue.size()); | 
| 310 |     while (!queue.isEmpty()) { | 
| 311 |         auto *child = queue.dequeue(); | 
| 312 |         auto *childEntity = qobject_cast<QEntity *>(object: child); | 
| 313 |         if (childEntity != nullptr) | 
| 314 |             data.childEntityIds.push_back(t: childEntity->id()); | 
| 315 |         else | 
| 316 |             queue.append(t: child->childNodes().toList()); | 
| 317 |     } | 
| 318 |  | 
| 319 |     data.componentIdsAndTypes.reserve(asize: d->m_components.size()); | 
| 320 |     const QComponentVector &components = d->m_components; | 
| 321 |     for (QComponent *c : components) { | 
| 322 |         const auto idAndType = QNodeIdTypePair(c->id(), QNodePrivate::findStaticMetaObject(metaObject: c->metaObject())); | 
| 323 |         data.componentIdsAndTypes.push_back(t: idAndType); | 
| 324 |     } | 
| 325 |  | 
| 326 |     return creationChange; | 
| 327 | } | 
| 328 |  | 
| 329 | void QEntity::onParentChanged(QObject *) | 
| 330 | { | 
| 331 |     Q_D(QEntity); | 
| 332 |     if (!d->m_hasBackendNode) | 
| 333 |         return; | 
| 334 |  | 
| 335 |     d->update(); | 
| 336 | } | 
| 337 |  | 
| 338 | } // namespace Qt3DCore | 
| 339 |  | 
| 340 | QT_END_NAMESPACE | 
| 341 |  |