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

source code of qt3d/src/render/backend/entity.cpp