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 "entity_p.h"
41#include <Qt3DRender/private/managers_p.h>
42#include <Qt3DRender/private/nodemanagers_p.h>
43#include <Qt3DRender/qabstractlight.h>
44#include <Qt3DRender/qenvironmentlight.h>
45#include <Qt3DRender/qlayer.h>
46#include <Qt3DRender/qlevelofdetail.h>
47#include <Qt3DRender/qraycaster.h>
48#include <Qt3DRender/qscreenraycaster.h>
49#include <Qt3DRender/qmaterial.h>
50#include <Qt3DRender/qmesh.h>
51#include <Qt3DRender/private/renderlogging_p.h>
52#include <Qt3DRender/private/sphere_p.h>
53#include <Qt3DRender/qshaderdata.h>
54#include <Qt3DRender/qgeometryrenderer.h>
55#include <Qt3DRender/qobjectpicker.h>
56#include <Qt3DRender/qcomputecommand.h>
57#include <Qt3DRender/private/geometryrenderermanager_p.h>
58#include <Qt3DRender/private/armature_p.h>
59
60#include <Qt3DRender/qcameralens.h>
61#include <Qt3DCore/qarmature.h>
62#include <Qt3DCore/qcomponentaddedchange.h>
63#include <Qt3DCore/qcomponentremovedchange.h>
64#include <Qt3DCore/qentity.h>
65#include <Qt3DCore/qpropertyupdatedchange.h>
66#include <Qt3DCore/qtransform.h>
67#include <Qt3DCore/private/qentity_p.h>
68#include <Qt3DCore/qnodecreatedchange.h>
69
70#include <QMatrix4x4>
71#include <QString>
72
73QT_BEGIN_NAMESPACE
74
75using namespace Qt3DCore;
76
77namespace Qt3DRender {
78namespace Render {
79
80Entity::Entity()
81 : BackendNode()
82 , m_nodeManagers(nullptr)
83 , m_boundingDirty(false)
84 , m_treeEnabled(true)
85{
86}
87
88Entity::~Entity()
89{
90 cleanup();
91}
92
93void Entity::cleanup()
94{
95 if (m_nodeManagers != nullptr) {
96 m_nodeManagers->worldMatrixManager()->releaseResource(peerId());
97 qCDebug(Render::RenderNodes) << Q_FUNC_INFO;
98 }
99 if (!m_parentEntityId.isNull())
100 markDirty(AbstractRenderer::EntityHierarchyDirty);
101
102 m_parentEntityId = Qt3DCore::QNodeId();
103 m_worldTransform = HMatrix();
104 // Release all component will have to perform their own release when they receive the
105 // NodeDeleted notification
106 // Clear components
107 m_transformComponent = Qt3DCore::QNodeId();
108 m_cameraComponent = Qt3DCore::QNodeId();
109 m_materialComponent = Qt3DCore::QNodeId();
110 m_geometryRendererComponent = Qt3DCore::QNodeId();
111 m_objectPickerComponent = QNodeId();
112 m_boundingVolumeDebugComponent = QNodeId();
113 m_computeComponent = QNodeId();
114 m_armatureComponent = QNodeId();
115 m_childrenHandles.clear();
116 m_layerComponents.clear();
117 m_levelOfDetailComponents.clear();
118 m_rayCasterComponents.clear();
119 m_shaderDataComponents.clear();
120 m_lightComponents.clear();
121 m_environmentLightComponents.clear();
122 m_localBoundingVolume.reset();
123 m_worldBoundingVolume.reset();
124 m_worldBoundingVolumeWithChildren.reset();
125 m_boundingDirty = false;
126 QBackendNode::setEnabled(false);
127}
128
129void Entity::setParentHandle(HEntity parentHandle)
130{
131 Q_ASSERT(m_nodeManagers);
132 m_parentHandle = parentHandle;
133 auto parent = m_nodeManagers->renderNodesManager()->data(parentHandle);
134 if (parent != nullptr && !parent->m_childrenHandles.contains(m_handle))
135 parent->m_childrenHandles.append(m_handle);
136}
137
138void Entity::setNodeManagers(NodeManagers *manager)
139{
140 m_nodeManagers = manager;
141}
142
143void Entity::setHandle(HEntity handle)
144{
145 m_handle = handle;
146}
147
148void Entity::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
149{
150 const auto typedChange = qSharedPointerCast<QNodeCreatedChange<Qt3DCore::QEntityData>>(change);
151 const auto &data = typedChange->data;
152
153 // Note this is *not* the parentId as that is the ID of the parent QNode, which is not
154 // necessarily the same as the parent QEntity (which may be further up the tree).
155 m_parentEntityId = data.parentEntityId;
156 qCDebug(Render::RenderNodes) << "Creating Entity id =" << peerId() << "parentId =" << m_parentEntityId;
157
158 // TODO: Store string id instead and only in debug mode
159 //m_objectName = peer->objectName();
160 m_worldTransform = m_nodeManagers->worldMatrixManager()->getOrAcquireHandle(peerId());
161
162 // TODO: Suboptimal -> Maybe have a Hash<QComponent, QEntityList> instead
163 m_transformComponent = QNodeId();
164 m_materialComponent = QNodeId();
165 m_cameraComponent = QNodeId();
166 m_geometryRendererComponent = QNodeId();
167 m_objectPickerComponent = QNodeId();
168 m_boundingVolumeDebugComponent = QNodeId();
169 m_computeComponent = QNodeId();
170 m_layerComponents.clear();
171 m_levelOfDetailComponents.clear();
172 m_rayCasterComponents.clear();
173 m_shaderDataComponents.clear();
174 m_lightComponents.clear();
175 m_environmentLightComponents.clear();
176 m_localBoundingVolume = QSharedPointer<Sphere>::create(peerId());
177 m_worldBoundingVolume = QSharedPointer<Sphere>::create(peerId());
178 m_worldBoundingVolumeWithChildren = QSharedPointer<Sphere>::create(peerId());
179
180 for (const auto &idAndType : qAsConst(data.componentIdsAndTypes))
181 addComponent(idAndType);
182
183 markDirty(AbstractRenderer::EntityHierarchyDirty);
184}
185
186void Entity::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
187{
188 switch (e->type()) {
189
190 case ComponentAdded: {
191 QComponentAddedChangePtr change = qSharedPointerCast<QComponentAddedChange>(e);
192 const auto componentIdAndType = QNodeIdTypePair(change->componentId(), change->componentMetaObject());
193 addComponent(componentIdAndType);
194 qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "Component Added. Id =" << change->componentId();
195 markDirty(AbstractRenderer::AllDirty);
196 break;
197 }
198
199 case ComponentRemoved: {
200 QComponentRemovedChangePtr change = qSharedPointerCast<QComponentRemovedChange>(e);
201 removeComponent(change->componentId());
202 qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "Component Removed. Id =" << change->componentId();
203 markDirty(AbstractRenderer::AllDirty);
204 break;
205 }
206
207 case PropertyUpdated: {
208 QPropertyUpdatedChangePtr change = qSharedPointerCast<QPropertyUpdatedChange>(e);
209 if (change->propertyName() == QByteArrayLiteral("enabled")) {
210 // We only mark as dirty the renderer
211 markDirty(AbstractRenderer::EntityEnabledDirty);
212 // We let QBackendNode::sceneChangeEvent change the enabled property
213 } else if (change->propertyName() == QByteArrayLiteral("parentEntityUpdated")) {
214 auto newParent = change->value().value<Qt3DCore::QNodeId>();
215 qCDebug(Render::RenderNodes) << "Setting parent for " << peerId() << ", new parentId =" << newParent;
216 if (m_parentEntityId != newParent) {
217 m_parentEntityId = newParent;
218 // TODO: change to EventHierarchyDirty and update renderer to
219 // ensure all jobs are run that depend on Entity hierarchy.
220 markDirty(AbstractRenderer::AllDirty);
221 }
222 }
223
224 break;
225 }
226
227 default:
228 break;
229 }
230 BackendNode::sceneChangeEvent(e);
231}
232
233void Entity::dump() const
234{
235 static int depth = 0;
236 QString indent(2 * depth++, QChar::fromLatin1(' '));
237 qCDebug(Backend) << indent + m_objectName;
238 const auto children_ = children();
239 for (const Entity *child : children_)
240 child->dump();
241 --depth;
242}
243
244Entity *Entity::parent() const
245{
246 return m_nodeManagers->renderNodesManager()->data(m_parentHandle);
247}
248
249
250// clearEntityHierarchy and rebuildEntityHierarchy should only be called
251// from UpdateEntityHierarchyJob to update the entity hierarchy for the
252// entire scene at once
253void Entity::clearEntityHierarchy()
254{
255 m_childrenHandles.clear();
256 m_parentHandle = HEntity();
257}
258
259// clearEntityHierarchy and rebuildEntityHierarchy should only be called
260// from UpdateEntityHierarchyJob to update the entity hierarchy for the
261// entire scene at once
262void Entity::rebuildEntityHierarchy()
263{
264 if (!m_parentEntityId.isNull())
265 setParentHandle(m_nodeManagers->renderNodesManager()->lookupHandle(m_parentEntityId));
266 else
267 qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "No parent entity found for Entity" << peerId();
268}
269
270void Entity::appendChildHandle(HEntity childHandle)
271{
272 if (!m_childrenHandles.contains(childHandle)) {
273 m_childrenHandles.append(childHandle);
274 Entity *child = m_nodeManagers->renderNodesManager()->data(childHandle);
275 if (child != nullptr)
276 child->m_parentHandle = m_handle;
277 }
278}
279
280QVector<Entity *> Entity::children() const
281{
282 QVector<Entity *> childrenVector;
283 childrenVector.reserve(m_childrenHandles.size());
284 for (const HEntity &handle : m_childrenHandles) {
285 Entity *child = m_nodeManagers->renderNodesManager()->data(handle);
286 if (child != nullptr)
287 childrenVector.append(child);
288 }
289 return childrenVector;
290}
291
292void Entity::traverse(const std::function<void(Entity *)> &operation)
293{
294 operation(this);
295 for (const HEntity &handle : qAsConst(m_childrenHandles)) {
296 Entity *child = m_nodeManagers->renderNodesManager()->data(handle);
297 if (child != nullptr)
298 child->traverse(operation);
299 }
300}
301
302void Entity::traverse(const std::function<void(const Entity *)> &operation) const
303{
304 operation(this);
305 for (const HEntity &handle : m_childrenHandles) {
306 const Entity *child = m_nodeManagers->renderNodesManager()->data(handle);
307 if (child != nullptr)
308 child->traverse(operation);
309 }
310}
311
312Matrix4x4 *Entity::worldTransform()
313{
314 return m_nodeManagers->worldMatrixManager()->data(m_worldTransform);
315}
316
317const Matrix4x4 *Entity::worldTransform() const
318{
319 return m_nodeManagers->worldMatrixManager()->data(m_worldTransform);
320}
321
322void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType)
323{
324 // The backend element is always created when this method is called
325 // If that's not the case something has gone wrong
326 const auto type = idAndType.type;
327 const auto id = idAndType.id;
328 qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "id =" << id << type->className();
329 if (type->inherits(&Qt3DCore::QTransform::staticMetaObject)) {
330 m_transformComponent = id;
331 } else if (type->inherits(&QCameraLens::staticMetaObject)) {
332 m_cameraComponent = id;
333 } else if (type->inherits(&QLayer::staticMetaObject)) {
334 m_layerComponents.append(id);
335 } else if (type->inherits(&QLevelOfDetail::staticMetaObject)) {
336 m_levelOfDetailComponents.append(id);
337 } else if (type->inherits(&QRayCaster::staticMetaObject)) {
338 m_rayCasterComponents.append(id);
339 } else if (type->inherits(&QScreenRayCaster::staticMetaObject)) {
340 m_rayCasterComponents.append(id);
341 } else if (type->inherits(&QMaterial::staticMetaObject)) {
342 m_materialComponent = id;
343 } else if (type->inherits(&QAbstractLight::staticMetaObject)) { // QAbstractLight subclasses QShaderData
344 m_lightComponents.append(id);
345 } else if (type->inherits(&QEnvironmentLight::staticMetaObject)) {
346 m_environmentLightComponents.append(id);
347 } else if (type->inherits(&QShaderData::staticMetaObject)) {
348 m_shaderDataComponents.append(id);
349 } else if (type->inherits(&QGeometryRenderer::staticMetaObject)) {
350 m_geometryRendererComponent = id;
351 m_boundingDirty = true;
352 } else if (type->inherits(&QObjectPicker::staticMetaObject)) {
353 m_objectPickerComponent = id;
354// } else if (type->inherits(&QBoundingVolumeDebug::staticMetaObject)) {
355// m_boundingVolumeDebugComponent = id;
356 } else if (type->inherits(&QComputeCommand::staticMetaObject)) {
357 m_computeComponent = id;
358 } else if (type->inherits(&QArmature::staticMetaObject)) {
359 m_armatureComponent = id;
360 }
361}
362
363void Entity::removeComponent(Qt3DCore::QNodeId nodeId)
364{
365 if (m_transformComponent == nodeId) {
366 m_transformComponent = QNodeId();
367 } else if (m_cameraComponent == nodeId) {
368 m_cameraComponent = QNodeId();
369 } else if (m_layerComponents.contains(nodeId)) {
370 m_layerComponents.removeAll(nodeId);
371 } else if (m_levelOfDetailComponents.contains(nodeId)) {
372 m_levelOfDetailComponents.removeAll(nodeId);
373 } else if (m_rayCasterComponents.contains(nodeId)) {
374 m_rayCasterComponents.removeAll(nodeId);
375 } else if (m_materialComponent == nodeId) {
376 m_materialComponent = QNodeId();
377 } else if (m_shaderDataComponents.contains(nodeId)) {
378 m_shaderDataComponents.removeAll(nodeId);
379 } else if (m_geometryRendererComponent == nodeId) {
380 m_geometryRendererComponent = QNodeId();
381 m_boundingDirty = true;
382 } else if (m_objectPickerComponent == nodeId) {
383 m_objectPickerComponent = QNodeId();
384// } else if (m_boundingVolumeDebugComponent == nodeId) {
385// m_boundingVolumeDebugComponent = QNodeId();
386 } else if (m_lightComponents.contains(nodeId)) {
387 m_lightComponents.removeAll(nodeId);
388 } else if (m_environmentLightComponents.contains(nodeId)) {
389 m_environmentLightComponents.removeAll(nodeId);
390 } else if (m_computeComponent == nodeId) {
391 m_computeComponent = QNodeId();
392 } else if (m_armatureComponent == nodeId) {
393 m_armatureComponent = QNodeId();
394 }
395}
396
397bool Entity::isBoundingVolumeDirty() const
398{
399 return m_boundingDirty;
400}
401
402void Entity::unsetBoundingVolumeDirty()
403{
404 m_boundingDirty = false;
405}
406
407void Entity::addRecursiveLayerId(const QNodeId layerId)
408{
409 if (!m_recursiveLayerComponents.contains(layerId) && !m_layerComponents.contains(layerId))
410 m_recursiveLayerComponents.push_back(layerId);
411}
412
413void Entity::removeRecursiveLayerId(const QNodeId layerId)
414{
415 m_recursiveLayerComponents.removeOne(layerId);
416}
417
418ENTITY_COMPONENT_TEMPLATE_IMPL(Material, HMaterial, MaterialManager, m_materialComponent)
419ENTITY_COMPONENT_TEMPLATE_IMPL(CameraLens, HCamera, CameraManager, m_cameraComponent)
420ENTITY_COMPONENT_TEMPLATE_IMPL(Transform, HTransform, TransformManager, m_transformComponent)
421ENTITY_COMPONENT_TEMPLATE_IMPL(GeometryRenderer, HGeometryRenderer, GeometryRendererManager, m_geometryRendererComponent)
422ENTITY_COMPONENT_TEMPLATE_IMPL(ObjectPicker, HObjectPicker, ObjectPickerManager, m_objectPickerComponent)
423ENTITY_COMPONENT_TEMPLATE_IMPL(ComputeCommand, HComputeCommand, ComputeCommandManager, m_computeComponent)
424ENTITY_COMPONENT_TEMPLATE_IMPL(Armature, HArmature, ArmatureManager, m_armatureComponent)
425ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(Layer, HLayer, LayerManager, m_layerComponents)
426ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(LevelOfDetail, HLevelOfDetail, LevelOfDetailManager, m_levelOfDetailComponents)
427ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(RayCaster, HRayCaster, RayCasterManager, m_rayCasterComponents)
428ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(ShaderData, HShaderData, ShaderDataManager, m_shaderDataComponents)
429ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(Light, HLight, LightManager, m_lightComponents)
430ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(EnvironmentLight, HEnvironmentLight, EnvironmentLightManager, m_environmentLightComponents)
431
432RenderEntityFunctor::RenderEntityFunctor(AbstractRenderer *renderer, NodeManagers *manager)
433 : m_nodeManagers(manager)
434 , m_renderer(renderer)
435{
436}
437
438Qt3DCore::QBackendNode *RenderEntityFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const
439{
440 HEntity renderNodeHandle = m_nodeManagers->renderNodesManager()->getOrAcquireHandle(change->subjectId());
441 Entity *entity = m_nodeManagers->renderNodesManager()->data(renderNodeHandle);
442 entity->setNodeManagers(m_nodeManagers);
443 entity->setHandle(renderNodeHandle);
444 entity->setRenderer(m_renderer);
445 return entity;
446}
447
448Qt3DCore::QBackendNode *RenderEntityFunctor::get(Qt3DCore::QNodeId id) const
449{
450 return m_nodeManagers->renderNodesManager()->lookupResource(id);
451}
452
453void RenderEntityFunctor::destroy(Qt3DCore::QNodeId id) const
454{
455 m_nodeManagers->renderNodesManager()->releaseResource(id);
456}
457
458} // namespace Render
459} // namespace Qt3DRender
460
461QT_END_NAMESPACE
462