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

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