blob: d766baaaff1e341b9577c4bb167ceb7dfc20c000 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "entity_p.h"
#include "entity_p_p.h"
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/qabstractlight.h>
#include <Qt3DRender/qenvironmentlight.h>
#include <Qt3DRender/qlayer.h>
#include <Qt3DRender/qlevelofdetail.h>
#include <Qt3DRender/qraycaster.h>
#include <Qt3DRender/qscreenraycaster.h>
#include <Qt3DRender/qmaterial.h>
#include <Qt3DRender/qmesh.h>
#include <Qt3DRender/private/renderlogging_p.h>
#include <Qt3DRender/private/sphere_p.h>
#include <Qt3DRender/qshaderdata.h>
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/qobjectpicker.h>
#include <Qt3DRender/qcomputecommand.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/armature_p.h>
#include <Qt3DRender/qcameralens.h>
#include <Qt3DCore/qarmature.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qtransform.h>
#include <Qt3DCore/private/qentity_p.h>
#include <Qt3DCore/qnodecreatedchange.h>
#include <QMatrix4x4>
#include <QString>
QT_BEGIN_NAMESPACE
using namespace Qt3DCore;
namespace Qt3DRender {
namespace Render {
EntityPrivate::EntityPrivate()
: Qt3DCore::QBackendNodePrivate(Entity::ReadOnly)
{
}
EntityPrivate *EntityPrivate::get(Entity *node)
{
return node->d_func();
}
void EntityPrivate::componentAdded(Qt3DCore::QNode *frontend)
{
Q_Q(Entity);
const auto componentIdAndType = QNodeIdTypePair(frontend->id(), QNodePrivate::findStaticMetaObject(frontend->metaObject()));
q->addComponent(componentIdAndType);
}
void EntityPrivate::componentRemoved(Qt3DCore::QNode *frontend)
{
Q_Q(Entity);
q->removeComponent(frontend->id());
}
Entity::Entity()
: BackendNode(*new EntityPrivate)
, m_nodeManagers(nullptr)
, m_boundingDirty(false)
, m_treeEnabled(true)
{
}
Entity::~Entity()
{
cleanup();
}
void Entity::cleanup()
{
if (m_nodeManagers != nullptr) {
m_nodeManagers->worldMatrixManager()->releaseResource(peerId());
qCDebug(Render::RenderNodes) << Q_FUNC_INFO;
removeFromParentChildHandles();
for (auto &childHandle : qAsConst(m_childrenHandles)) {
auto child = m_nodeManagers->renderNodesManager()->data(childHandle);
// children should always exist and have this as parent
// if they were destroyed, they would have removed themselves from our m_childrenHandles
Q_ASSERT(child);
Q_ASSERT(child->m_parentHandle == m_handle);
child->m_parentHandle = {};
}
}
m_worldTransform = HMatrix();
// Release all component will have to perform their own release when they receive the
// NodeDeleted notification
// Clear components
m_transformComponent = Qt3DCore::QNodeId();
m_cameraComponent = Qt3DCore::QNodeId();
m_materialComponent = Qt3DCore::QNodeId();
m_geometryRendererComponent = Qt3DCore::QNodeId();
m_objectPickerComponent = QNodeId();
m_boundingVolumeDebugComponent = QNodeId();
m_computeComponent = QNodeId();
m_armatureComponent = QNodeId();
m_childrenHandles.clear();
m_layerComponents.clear();
m_levelOfDetailComponents.clear();
m_rayCasterComponents.clear();
m_shaderDataComponents.clear();
m_lightComponents.clear();
m_environmentLightComponents.clear();
m_localBoundingVolume.reset();
m_worldBoundingVolume.reset();
m_worldBoundingVolumeWithChildren.reset();
m_parentHandle = {};
m_boundingDirty = false;
QBackendNode::setEnabled(false);
// Ensure we rebuild caches when an Entity gets cleaned up
if (m_renderer)
markDirty(AbstractRenderer::AllDirty);
}
void Entity::setParentHandle(HEntity parentHandle)
{
Q_ASSERT(m_nodeManagers);
if (parentHandle == m_parentHandle)
return;
removeFromParentChildHandles();
m_parentHandle = parentHandle;
auto parent = m_nodeManagers->renderNodesManager()->data(parentHandle);
if (parent != nullptr && !parent->m_childrenHandles.contains(m_handle))
parent->m_childrenHandles.append(m_handle);
}
void Entity::setNodeManagers(NodeManagers *manager)
{
m_nodeManagers = manager;
}
void Entity::setHandle(HEntity handle)
{
m_handle = handle;
}
void Entity::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
{
const Qt3DCore::QEntity *node = qobject_cast<const Qt3DCore::QEntity *>(frontEnd);
if (!node)
return;
if (this->isEnabled() != node->isEnabled()) {
markDirty(AbstractRenderer::EntityEnabledDirty);
// We let QBackendNode::syncFromFrontEnd change the enabled property
}
const auto parentID = node->parentEntity() ? node->parentEntity()->id() : Qt3DCore::QNodeId();
auto parentHandle = m_nodeManagers->renderNodesManager()->lookupHandle(parentID);
// All entity creation is done from top-down and always during the same frame, so
// we if we have a valid parent node, we should always be able to resolve the
// backend parent at this time
Q_ASSERT(!node->parentEntity() || (!parentHandle.isNull() && m_nodeManagers->renderNodesManager()->data(parentHandle)));
if (parentHandle != m_parentHandle) {
markDirty(AbstractRenderer::AllDirty);
}
setParentHandle(parentHandle);
if (firstTime) {
m_worldTransform = m_nodeManagers->worldMatrixManager()->getOrAcquireHandle(peerId());
// TODO: Suboptimal -> Maybe have a Hash<QComponent, QEntityList> instead
m_transformComponent = QNodeId();
m_materialComponent = QNodeId();
m_cameraComponent = QNodeId();
m_geometryRendererComponent = QNodeId();
m_objectPickerComponent = QNodeId();
m_boundingVolumeDebugComponent = QNodeId();
m_computeComponent = QNodeId();
m_layerComponents.clear();
m_levelOfDetailComponents.clear();
m_rayCasterComponents.clear();
m_shaderDataComponents.clear();
m_lightComponents.clear();
m_environmentLightComponents.clear();
m_localBoundingVolume = QSharedPointer<Sphere>::create(peerId());
m_worldBoundingVolume = QSharedPointer<Sphere>::create(peerId());
m_worldBoundingVolumeWithChildren = QSharedPointer<Sphere>::create(peerId());
const QComponentVector &components = node->components();
for (QComponent *c : components) {
const auto idAndType = QNodeIdTypePair(c->id(), QNodePrivate::findStaticMetaObject(c->metaObject()));
addComponent(idAndType);
}
}
BackendNode::syncFromFrontEnd(frontEnd, firstTime);
}
void Entity::dump() const
{
static int depth = 0;
QString indent(2 * depth++, QChar::fromLatin1(' '));
qCDebug(Backend) << indent + m_objectName;
const auto children_ = children();
for (const Entity *child : children_)
child->dump();
--depth;
}
Entity *Entity::parent() const
{
return m_nodeManagers->renderNodesManager()->data(m_parentHandle);
}
void Entity::removeFromParentChildHandles()
{
// remove ourself from our parent's list of children.
auto p = parent();
if (p)
p->removeChildHandle(m_handle);
}
QVector<Entity *> Entity::children() const
{
QVector<Entity *> childrenVector;
childrenVector.reserve(m_childrenHandles.size());
for (const HEntity &handle : m_childrenHandles) {
Entity *child = m_nodeManagers->renderNodesManager()->data(handle);
if (child != nullptr)
childrenVector.append(child);
}
return childrenVector;
}
void Entity::traverse(const std::function<void(Entity *)> &operation)
{
operation(this);
for (const HEntity &handle : qAsConst(m_childrenHandles)) {
Entity *child = m_nodeManagers->renderNodesManager()->data(handle);
if (child != nullptr)
child->traverse(operation);
}
}
void Entity::traverse(const std::function<void(const Entity *)> &operation) const
{
operation(this);
for (const HEntity &handle : m_childrenHandles) {
const Entity *child = m_nodeManagers->renderNodesManager()->data(handle);
if (child != nullptr)
child->traverse(operation);
}
}
Matrix4x4 *Entity::worldTransform()
{
return m_nodeManagers->worldMatrixManager()->data(m_worldTransform);
}
const Matrix4x4 *Entity::worldTransform() const
{
return m_nodeManagers->worldMatrixManager()->data(m_worldTransform);
}
void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType)
{
// The backend element is always created when this method is called
// If that's not the case something has gone wrong
const auto type = idAndType.type;
const auto id = idAndType.id;
qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "id =" << id << type->className();
if (type->inherits(&Qt3DCore::QTransform::staticMetaObject)) {
m_transformComponent = id;
} else if (type->inherits(&QCameraLens::staticMetaObject)) {
m_cameraComponent = id;
} else if (type->inherits(&QLayer::staticMetaObject)) {
m_layerComponents.append(id);
} else if (type->inherits(&QLevelOfDetail::staticMetaObject)) {
m_levelOfDetailComponents.append(id);
} else if (type->inherits(&QRayCaster::staticMetaObject)) {
m_rayCasterComponents.append(id);
} else if (type->inherits(&QScreenRayCaster::staticMetaObject)) {
m_rayCasterComponents.append(id);
} else if (type->inherits(&QMaterial::staticMetaObject)) {
m_materialComponent = id;
} else if (type->inherits(&QAbstractLight::staticMetaObject)) { // QAbstractLight subclasses QShaderData
m_lightComponents.append(id);
} else if (type->inherits(&QEnvironmentLight::staticMetaObject)) {
m_environmentLightComponents.append(id);
} else if (type->inherits(&QShaderData::staticMetaObject)) {
m_shaderDataComponents.append(id);
} else if (type->inherits(&QGeometryRenderer::staticMetaObject)) {
m_geometryRendererComponent = id;
m_boundingDirty = true;
} else if (type->inherits(&QObjectPicker::staticMetaObject)) {
m_objectPickerComponent = id;
// } else if (type->inherits(&QBoundingVolumeDebug::staticMetaObject)) {
// m_boundingVolumeDebugComponent = id;
} else if (type->inherits(&QComputeCommand::staticMetaObject)) {
m_computeComponent = id;
} else if (type->inherits(&QArmature::staticMetaObject)) {
m_armatureComponent = id;
}
markDirty(AbstractRenderer::AllDirty);
}
void Entity::removeComponent(Qt3DCore::QNodeId nodeId)
{
if (m_transformComponent == nodeId) {
m_transformComponent = QNodeId();
} else if (m_cameraComponent == nodeId) {
m_cameraComponent = QNodeId();
} else if (m_layerComponents.contains(nodeId)) {
m_layerComponents.removeAll(nodeId);
} else if (m_levelOfDetailComponents.contains(nodeId)) {
m_levelOfDetailComponents.removeAll(nodeId);
} else if (m_rayCasterComponents.contains(nodeId)) {
m_rayCasterComponents.removeAll(nodeId);
} else if (m_materialComponent == nodeId) {
m_materialComponent = QNodeId();
} else if (m_shaderDataComponents.contains(nodeId)) {
m_shaderDataComponents.removeAll(nodeId);
} else if (m_geometryRendererComponent == nodeId) {
m_geometryRendererComponent = QNodeId();
m_boundingDirty = true;
} else if (m_objectPickerComponent == nodeId) {
m_objectPickerComponent = QNodeId();
// } else if (m_boundingVolumeDebugComponent == nodeId) {
// m_boundingVolumeDebugComponent = QNodeId();
} else if (m_lightComponents.contains(nodeId)) {
m_lightComponents.removeAll(nodeId);
} else if (m_environmentLightComponents.contains(nodeId)) {
m_environmentLightComponents.removeAll(nodeId);
} else if (m_computeComponent == nodeId) {
m_computeComponent = QNodeId();
} else if (m_armatureComponent == nodeId) {
m_armatureComponent = QNodeId();
}
markDirty(AbstractRenderer::AllDirty);
}
bool Entity::isBoundingVolumeDirty() const
{
return m_boundingDirty;
}
void Entity::unsetBoundingVolumeDirty()
{
m_boundingDirty = false;
}
void Entity::addRecursiveLayerId(const QNodeId layerId)
{
if (!m_recursiveLayerComponents.contains(layerId) && !m_layerComponents.contains(layerId))
m_recursiveLayerComponents.push_back(layerId);
}
void Entity::removeRecursiveLayerId(const QNodeId layerId)
{
m_recursiveLayerComponents.removeOne(layerId);
}
ENTITY_COMPONENT_TEMPLATE_IMPL(Material, HMaterial, MaterialManager, m_materialComponent)
ENTITY_COMPONENT_TEMPLATE_IMPL(CameraLens, HCamera, CameraManager, m_cameraComponent)
ENTITY_COMPONENT_TEMPLATE_IMPL(Transform, HTransform, TransformManager, m_transformComponent)
ENTITY_COMPONENT_TEMPLATE_IMPL(GeometryRenderer, HGeometryRenderer, GeometryRendererManager, m_geometryRendererComponent)
ENTITY_COMPONENT_TEMPLATE_IMPL(ObjectPicker, HObjectPicker, ObjectPickerManager, m_objectPickerComponent)
ENTITY_COMPONENT_TEMPLATE_IMPL(ComputeCommand, HComputeCommand, ComputeCommandManager, m_computeComponent)
ENTITY_COMPONENT_TEMPLATE_IMPL(Armature, HArmature, ArmatureManager, m_armatureComponent)
ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(Layer, HLayer, LayerManager, m_layerComponents)
ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(LevelOfDetail, HLevelOfDetail, LevelOfDetailManager, m_levelOfDetailComponents)
ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(RayCaster, HRayCaster, RayCasterManager, m_rayCasterComponents)
ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(ShaderData, HShaderData, ShaderDataManager, m_shaderDataComponents)
ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(Light, HLight, LightManager, m_lightComponents)
ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(EnvironmentLight, HEnvironmentLight, EnvironmentLightManager, m_environmentLightComponents)
RenderEntityFunctor::RenderEntityFunctor(AbstractRenderer *renderer, NodeManagers *manager)
: m_nodeManagers(manager)
, m_renderer(renderer)
{
}
Qt3DCore::QBackendNode *RenderEntityFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const
{
HEntity renderNodeHandle = m_nodeManagers->renderNodesManager()->getOrAcquireHandle(change->subjectId());
Entity *entity = m_nodeManagers->renderNodesManager()->data(renderNodeHandle);
entity->setNodeManagers(m_nodeManagers);
entity->setHandle(renderNodeHandle);
entity->setRenderer(m_renderer);
return entity;
}
Qt3DCore::QBackendNode *RenderEntityFunctor::get(Qt3DCore::QNodeId id) const
{
return m_nodeManagers->renderNodesManager()->lookupResource(id);
}
void RenderEntityFunctor::destroy(Qt3DCore::QNodeId id) const
{
m_nodeManagers->renderNodesManager()->releaseResource(id);
}
} // namespace Render
} // namespace Qt3DRender
QT_END_NAMESPACE