diff options
author | Sean Harmer <sean.harmer@kdab.com> | 2018-02-05 13:01:09 +0000 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2018-02-05 15:42:29 +0000 |
commit | 0403ee45736241aa621eb3d38880a4fff571fd96 (patch) | |
tree | 94650145a3b7e2517dfcf29d33f97859933b518d /src | |
parent | 04afcf1cb9e79697360baa01a97a26815237eba1 (diff) | |
parent | ceae743678d41a58154612781e896c04c87a8c4f (diff) |
Merge remote-tracking branch 'origin/5.9' into 5.10
Conflicts:
.qmake.conf
src/render/backend/trianglesvisitor.cpp
src/render/backend/uniform.cpp
src/render/jobs/calcboundingvolumejob.cpp
src/render/jobs/pickboundingvolumejob.cpp
src/render/jobs/pickboundingvolumeutils.cpp
Change-Id: Ib8305011c51710a3538c0b29f7022388f5244a38
Diffstat (limited to 'src')
34 files changed, 417 insertions, 201 deletions
diff --git a/src/core/changes/qcomponentaddedchange.cpp b/src/core/changes/qcomponentaddedchange.cpp index e00c4ffab..41f7a2340 100644 --- a/src/core/changes/qcomponentaddedchange.cpp +++ b/src/core/changes/qcomponentaddedchange.cpp @@ -75,7 +75,7 @@ QComponentAddedChangePrivate::QComponentAddedChangePrivate(const QEntity *entity */ /*! - * Constructs a new QComponentAddedChange with with \a entity and \a component. + * Constructs a new QComponentAddedChange which will notify \a entity that \a component was added */ QComponentAddedChange::QComponentAddedChange(const QEntity *entity, const QComponent *component) @@ -84,6 +84,16 @@ QComponentAddedChange::QComponentAddedChange(const QEntity *entity, { } +/*! + * Constructs a new QComponentAddedChange which will notify \a component that it was added to \a entity + */ +QComponentAddedChange::QComponentAddedChange(const QComponent *component, + const QEntity *entity) + : QSceneChange(*new QComponentAddedChangePrivate(entity, component), + ComponentAdded, component->id()) +{ +} + QComponentAddedChange::~QComponentAddedChange() { } diff --git a/src/core/changes/qcomponentaddedchange.h b/src/core/changes/qcomponentaddedchange.h index a62cac116..e7676a026 100644 --- a/src/core/changes/qcomponentaddedchange.h +++ b/src/core/changes/qcomponentaddedchange.h @@ -55,6 +55,8 @@ class QT3DCORESHARED_EXPORT QComponentAddedChange : public QSceneChange public: explicit QComponentAddedChange(const QEntity *entity, const QComponent *component); + explicit QComponentAddedChange(const QComponent *component, + const QEntity *entity); ~QComponentAddedChange(); QNodeId entityId() const Q_DECL_NOTHROW; diff --git a/src/core/changes/qcomponentremovedchange.cpp b/src/core/changes/qcomponentremovedchange.cpp index 5e5dfa5aa..e2129169a 100644 --- a/src/core/changes/qcomponentremovedchange.cpp +++ b/src/core/changes/qcomponentremovedchange.cpp @@ -75,7 +75,7 @@ QComponentRemovedChangePrivate::QComponentRemovedChangePrivate(const QEntity *en */ /*! - * Constructs a new QComponentRemovedChange with \a entity and \a component. + * Constructs a new QComponentRemovedChange which will notify \a entity that \a component was removed. */ QComponentRemovedChange::QComponentRemovedChange(const QEntity *entity, const QComponent *component) @@ -84,6 +84,17 @@ QComponentRemovedChange::QComponentRemovedChange(const QEntity *entity, { } +/*! + * Constructs a new QComponentRemovedChange which will notify \a component that it was removed from \a entity + */ +QComponentRemovedChange::QComponentRemovedChange(const QComponent *component, + const QEntity *entity) + : QSceneChange(*new QComponentRemovedChangePrivate(entity, component), + ComponentRemoved, component->id()) +{ + +} + QComponentRemovedChange::~QComponentRemovedChange() { } diff --git a/src/core/changes/qcomponentremovedchange.h b/src/core/changes/qcomponentremovedchange.h index 3c57fe26f..66743b1ae 100644 --- a/src/core/changes/qcomponentremovedchange.h +++ b/src/core/changes/qcomponentremovedchange.h @@ -55,6 +55,8 @@ class QT3DCORESHARED_EXPORT QComponentRemovedChange : public QSceneChange public: explicit QComponentRemovedChange(const QEntity *entity, const QComponent *component); + explicit QComponentRemovedChange(const QComponent *component, + const QEntity *entity); ~QComponentRemovedChange(); QNodeId entityId() const Q_DECL_NOTHROW; diff --git a/src/core/changes/qpropertynodeaddedchange.cpp b/src/core/changes/qpropertynodeaddedchange.cpp index 390a170b6..9f8e50872 100644 --- a/src/core/changes/qpropertynodeaddedchange.cpp +++ b/src/core/changes/qpropertynodeaddedchange.cpp @@ -76,6 +76,16 @@ QPropertyNodeAddedChange::QPropertyNodeAddedChange(QNodeId subjectId, QNode *nod { Q_D(QPropertyNodeAddedChange); d->m_addedNodeIdTypePair = QNodeIdTypePair(node->id(), QNodePrivate::findStaticMetaObject(node->metaObject())); + + // Ensure the node has issued a node creation change. We can end + // up here if a newly created node with a parent is immediately set + // as a property on another node. In this case the deferred call to + // _q_postConstructorInit() will not have happened yet as the event + // loop will still be blocked. So force it here and we catch this + // eventuality in the _q_postConstructorInit() function so that we + // do not repeat the creation and new child scene change events. + if (node) + QNodePrivate::get(node)->_q_postConstructorInit(); } /*! \internal */ diff --git a/src/core/nodes/qcomponent.cpp b/src/core/nodes/qcomponent.cpp index 8e337adf6..f4e59e058 100644 --- a/src/core/nodes/qcomponent.cpp +++ b/src/core/nodes/qcomponent.cpp @@ -73,7 +73,7 @@ void QComponentPrivate::addEntity(QEntity *entity) m_scene->addEntityForComponent(m_id, entity->id()); } - const auto componentAddedChange = QComponentAddedChangePtr::create(entity, q); + const auto componentAddedChange = QComponentAddedChangePtr::create(q, entity); notifyObservers(componentAddedChange); Q_EMIT q->addedToEntity(entity); } @@ -86,7 +86,7 @@ void QComponentPrivate::removeEntity(QEntity *entity) m_entities.removeAll(entity); - const auto componentRemovedChange = QComponentRemovedChangePtr::create(entity, q); + const auto componentRemovedChange = QComponentRemovedChangePtr::create(q, entity); notifyObservers(componentRemovedChange); Q_EMIT q->removedFromEntity(entity); } diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp index dbe3fd102..083fda7df 100644 --- a/src/core/nodes/qnode.cpp +++ b/src/core/nodes/qnode.cpp @@ -74,6 +74,7 @@ QNodePrivate::QNodePrivate() , m_blockNotifications(false) , m_hasBackendNode(false) , m_enabled(true) + , m_notifiedParent(false) , m_defaultPropertyTrackMode(QNode::TrackFinalValues) , m_propertyChangesSetup(false) , m_signals(this) @@ -210,13 +211,19 @@ void QNodePrivate::_q_addChild(QNode *childNode) Q_ASSERT(childNode); Q_ASSERT_X(childNode->parent() == q_func(), Q_FUNC_INFO, "not a child of this node"); + // Have we already notified the parent about its new child? If so, bail out + // early so that we do not send more than one new child event to the backend + QNodePrivate *childD = QNodePrivate::get(childNode); + if (childD->m_notifiedParent == true) + return; + // Store our id as the parentId in the child so that even if the child gets // removed from the scene as part of the destruction of the parent, when the // parent's children are deleted in the QObject dtor, we still have access to // the parentId. If we didn't store this, we wouldn't have access at that time // because the parent would then only be a QObject, the QNode part would have // been destroyed already. - QNodePrivate::get(childNode)->m_parentId = m_id; + childD->m_parentId = m_id; if (!m_scene) return; @@ -224,6 +231,11 @@ void QNodePrivate::_q_addChild(QNode *childNode) // We need to send a QPropertyNodeAddedChange to the backend // to notify the backend that we have a new child if (m_changeArbiter != nullptr) { + // Flag that we have notified the parent. We do this immediately before + // creating the change because that recurses back into this function and + // we need to catch that to avoid sending more than one new child event + // to the backend. + childD->m_notifiedParent = true; const auto change = QPropertyNodeAddedChangePtr::create(m_id, childNode); change->setPropertyName("children"); notifyObservers(change); @@ -299,6 +311,9 @@ void QNodePrivate::_q_setParentHelper(QNode *parent) notifyDestructionChangesAndRemoveFromScene(); } + // Flag that we need to notify any new parent + m_notifiedParent = false; + // Basically QObject::setParent but for QObjectPrivate QObjectPrivate::setParent_helper(parent); QNode *newParentNode = q->parentNode(); @@ -373,28 +388,43 @@ void QNodePrivate::propertyChanged(int propertyIndex) if (m_blockNotifications) return; + const auto toBackendValue = [this](const QVariant &data) -> QVariant + { + if (data.canConvert<QNode*>()) { + QNode *node = data.value<QNode*>(); + + // Ensure the node has issued a node creation change. We can end + // up here if a newly created node with a parent is immediately set + // as a property on another node. In this case the deferred call to + // _q_postConstructorInit() will not have happened yet as the event + // loop will still be blocked. So force it here and we catch this + // eventuality in the _q_postConstructorInit() function so that we + // do not repeat the creation and new child scene change events. + if (node) + QNodePrivate::get(node)->_q_postConstructorInit(); + + const QNodeId id = node ? node->id() : QNodeId(); + return QVariant::fromValue(id); + } + + return data; + }; + Q_Q(QNode); const QMetaProperty property = q->metaObject()->property(propertyIndex); const QVariant data = property.read(q); - if (data.canConvert<QNode*>()) { - QNode *node = data.value<QNode*>(); - - // Ensure the node has issued a node creation change. We can end - // up here if a newly created node with a parent is immediately set - // as a property on another node. In this case the deferred call to - // _q_postConstructorInit() will not have happened yet as the event - // loop will still be blocked. So force it here and we catch this - // eventuality in the _q_postConstructorInit() function so that we - // do not repeat the creation and new child scene change events. - if (node) - QNodePrivate::get(node)->_q_postConstructorInit(); - - const QNodeId id = node ? node->id() : QNodeId(); - notifyPropertyChange(property.name(), QVariant::fromValue(id)); + + if (data.type() == QVariant::List) { + QSequentialIterable iterable = data.value<QSequentialIterable>(); + QVariantList variants; + variants.reserve(iterable.size()); + for (const auto &v : iterable) + variants.append(toBackendValue(v)); + notifyPropertyChange(property.name(), variants); } else { - notifyPropertyChange(property.name(), data); + notifyPropertyChange(property.name(), toBackendValue(data)); } } diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h index ad9d2376e..87a0226f1 100644 --- a/src/core/nodes/qnode_p.h +++ b/src/core/nodes/qnode_p.h @@ -100,6 +100,7 @@ public: bool m_blockNotifications; bool m_hasBackendNode; bool m_enabled; + bool m_notifiedParent; QNode::PropertyTrackingMode m_defaultPropertyTrackMode; QHash<QString, QNode::PropertyTrackingMode> m_trackedPropertiesOverrides; @@ -137,10 +138,11 @@ public: static const QMetaObject *findStaticMetaObject(const QMetaObject *metaObject); + void _q_postConstructorInit(); + private: void notifyCreationChange(); void notifyDestructionChangesAndRemoveFromScene(); - void _q_postConstructorInit(); void _q_addChild(QNode *childNode); void _q_removeChild(QNode *childNode); void _q_setParentHelper(QNode *parent); diff --git a/src/doc/src/qt3danimation-module.qdoc b/src/doc/src/qt3danimation-module.qdoc index ed3406aa4..a926df67d 100644 --- a/src/doc/src/qt3danimation-module.qdoc +++ b/src/doc/src/qt3danimation-module.qdoc @@ -30,7 +30,7 @@ \module Qt3DAnimation \title Qt 3D Animation C++ Classes - \brief The Qt 3D Animation modules provides a set of prebuilt elements to help + \brief The Qt 3D Animation module provides a set of prebuilt elements to help you get started with Qt 3D. This module is still in tech preview. This means it is unstable, likely to diff --git a/src/doc/src/qt3dextras-module.qdoc b/src/doc/src/qt3dextras-module.qdoc index b9a7cc28a..facd4ef84 100644 --- a/src/doc/src/qt3dextras-module.qdoc +++ b/src/doc/src/qt3dextras-module.qdoc @@ -41,7 +41,7 @@ \module Qt3DExtras \title Qt 3D Extras C++ Classes - \brief The Qt 3D Extras modules provides a set of prebuilt elements to help + \brief The Qt 3D Extras module provides a set of prebuilt elements to help you get started with Qt 3D. This module is still in tech preview. This means it is unstable, likely to diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.cpp b/src/plugins/sceneparsers/assimp/assimpimporter.cpp index 6611a2529..50fd59b38 100644 --- a/src/plugins/sceneparsers/assimp/assimpimporter.cpp +++ b/src/plugins/sceneparsers/assimp/assimpimporter.cpp @@ -227,13 +227,13 @@ QAttribute *createAttribute(QBuffer *buffer, return attribute; } -QAttribute *createAttribute(QBuffer *buffer, - QAttribute::VertexBaseType vertexBaseType, - uint vertexSize, - uint count, - uint byteOffset = 0, - uint byteStride = 0, - QNode *parent = nullptr) +QAttribute *createIndexAttribute(QBuffer *buffer, + QAttribute::VertexBaseType vertexBaseType, + uint vertexSize, + uint count, + uint byteOffset = 0, + uint byteStride = 0, + QNode *parent = nullptr) { QAttribute *attribute = QAbstractNodeFactory::createNode<QAttribute>("QAttribute"); attribute->setBuffer(buffer); @@ -603,7 +603,8 @@ void AssimpImporter::readSceneFile(const QString &path) aiProcess_GenSmoothNormals| aiProcess_FlipUVs); if (m_scene->m_aiScene == nullptr) { - qCWarning(AssimpImporterLog) << "Assimp scene import failed"; + qCWarning(AssimpImporterLog) << "Assimp scene import failed" << m_scene->m_importer->GetErrorString(); + QSceneImporter::logError(QString::fromUtf8(m_scene->m_importer->GetErrorString())); return ; } parse(); @@ -828,7 +829,7 @@ QGeometryRenderer *AssimpImporter::loadMesh(uint meshIndex) indexBuffer->setData(ibufferContent); // Add indices attributes - QAttribute *indexAttribute = createAttribute(indexBuffer, indiceType, 1, indices); + QAttribute *indexAttribute = createIndexAttribute(indexBuffer, indiceType, 1, indices); indexAttribute->setAttributeType(QAttribute::IndexAttribute); meshGeometry->addAttribute(indexAttribute); diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.h b/src/plugins/sceneparsers/assimp/assimpimporter.h index 068f6eed2..e8eda3079 100644 --- a/src/plugins/sceneparsers/assimp/assimpimporter.h +++ b/src/plugins/sceneparsers/assimp/assimpimporter.h @@ -143,7 +143,6 @@ private: QHash<aiTextureType, QString> m_textureToParameterName; QVector<Qt3DAnimation::QKeyframeAnimation *> m_animations; QVector<Qt3DAnimation::QMorphingAnimation *> m_morphAnimations; -// QMap<aiNode*, Light*> m_lights; }; QDir m_sceneDir; diff --git a/src/render/backend/buffervisitor_p.h b/src/render/backend/buffervisitor_p.h index 7149e21ae..f7214460f 100644 --- a/src/render/backend/buffervisitor_p.h +++ b/src/render/backend/buffervisitor_p.h @@ -95,39 +95,7 @@ public: Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z); Q_UNUSED(w); } - bool apply(const GeometryRenderer *renderer, const QString &attributeName) - { - if (renderer == nullptr || renderer->instanceCount() != 1) { - return false; - } - - Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId()); - - if (!geom) - return false; - - Attribute *attribute = nullptr; - - const auto attrIds = geom->attributes(); - for (const Qt3DCore::QNodeId attrId : attrIds) { - attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId); - if (attribute){ - if (attribute->name() == attributeName - || (attributeName == QStringLiteral("default") - && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) { - break; - } - } - attribute = nullptr; - } - - if (!attribute) - return false; - - return apply(attribute); - } - - bool apply(Qt3DRender::Render::Attribute *attribute) + bool apply(Qt3DRender::Render::Attribute *attribute, Qt3DRender::Render::Attribute *indexAttribute, int drawVertexCount) { if (attribute->vertexBaseType() != VertexBaseType) return false; @@ -136,12 +104,36 @@ public: auto data = m_manager->lookupResource<Buffer, BufferManager>(attribute->bufferId())->data(); auto buffer = BufferTypeInfo::castToType<VertexBaseType>(data, attribute->byteOffset()); - switch (dataSize) { - case 1: traverseCoordinates1(buffer, attribute->byteStride(), attribute->count()); break; - case 2: traverseCoordinates2(buffer, attribute->byteStride(), attribute->count()); break; - case 3: traverseCoordinates3(buffer, attribute->byteStride(), attribute->count()); break; - case 4: traverseCoordinates4(buffer, attribute->byteStride(), attribute->count()); break; - default: Q_UNREACHABLE(); + + if (indexAttribute) { + auto indexData = m_manager->lookupResource<Buffer, BufferManager>(indexAttribute->bufferId())->data(); + if (indexAttribute->vertexBaseType() == QAttribute::UnsignedShort) { + auto indexBuffer = BufferTypeInfo::castToType<QAttribute::UnsignedShort>(indexData, indexAttribute->byteOffset()); + switch (dataSize) { + case 1: traverseCoordinates1Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break; + case 2: traverseCoordinates2Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break; + case 3: traverseCoordinates3Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break; + case 4: traverseCoordinates4Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break; + default: Q_UNREACHABLE(); + } + } else { + auto indexBuffer = BufferTypeInfo::castToType<QAttribute::UnsignedInt>(indexData, indexAttribute->byteOffset()); + switch (dataSize) { + case 1: traverseCoordinates1Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break; + case 2: traverseCoordinates2Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break; + case 3: traverseCoordinates3Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break; + case 4: traverseCoordinates4Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break; + default: Q_UNREACHABLE(); + } + } + } else { + switch (dataSize) { + case 1: traverseCoordinates1(buffer, attribute->byteStride(), drawVertexCount); break; + case 2: traverseCoordinates2(buffer, attribute->byteStride(), drawVertexCount); break; + case 3: traverseCoordinates3(buffer, attribute->byteStride(), drawVertexCount); break; + case 4: traverseCoordinates4(buffer, attribute->byteStride(), drawVertexCount); break; + default: Q_UNREACHABLE(); + } } return true; @@ -161,42 +153,95 @@ protected: } } + template <typename Coordinate, typename IndexElem> + void traverseCoordinates1Indexed(Coordinate *coordinates, + const uint byteStride, + IndexElem *indices, + const uint count) + { + const uint stride = byteStride / sizeof(Coordinate); + for (uint i = 0; i < count; ++i) { + const uint n = stride * indices[i]; + visit(i, coordinates[n]); + } + } + template <typename Coordinate> void traverseCoordinates2(Coordinate *coordinates, const uint byteStride, const uint count) { - const uint stride = byteStride / sizeof(Coordinate); + const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 2; for (uint ndx = 0; ndx < count; ++ndx) { visit(ndx, coordinates[0], coordinates[1]); coordinates += stride; } } + + template <typename Coordinate, typename IndexElem> + void traverseCoordinates2Indexed(Coordinate *coordinates, + const uint byteStride, + IndexElem *indices, + const uint count) + { + const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 2; + for (uint i = 0; i < count; ++i) { + const uint n = stride * indices[i]; + visit(i, coordinates[n], coordinates[n + 1]); + } + } + template <typename Coordinate> void traverseCoordinates3(Coordinate *coordinates, const uint byteStride, const uint count) { - const uint stride = byteStride / sizeof(Coordinate); + const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 3; for (uint ndx = 0; ndx < count; ++ndx) { visit(ndx, coordinates[0], coordinates[1], coordinates[2]); coordinates += stride; } } + template <typename Coordinate, typename IndexElem> + void traverseCoordinates3Indexed(Coordinate *coordinates, + const uint byteStride, + IndexElem *indices, + const uint count) + { + const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 3; + for (uint i = 0; i < count; ++i) { + const uint n = stride * indices[i]; + visit(i, coordinates[n], coordinates[n + 1], coordinates[n + 2]); + } + } + template <typename Coordinate> void traverseCoordinates4(Coordinate *coordinates, const uint byteStride, const uint count) { - const uint stride = byteStride / sizeof(Coordinate); + const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 4; for (uint ndx = 0; ndx < count; ++ndx) { visit(ndx, coordinates[0], coordinates[1], coordinates[2], coordinates[3]); coordinates += stride; } } + template <typename Coordinate, typename IndexElem> + void traverseCoordinates4Indexed(Coordinate *coordinates, + const uint byteStride, + IndexElem *indices, + const uint count) + { + const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 4; + for (uint i = 0; i < count; ++i) { + const uint n = stride * indices[i]; + visit(i, coordinates[n], coordinates[n + 1], coordinates[n + 2], coordinates[n + 3]); + } + } + NodeManagers *m_manager; }; diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index f4440a7f8..092340cf1 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -2000,7 +2000,7 @@ void Renderer::cleanGraphicsResources() } } -QList<QMouseEvent> Renderer::pendingPickingEvents() const +QList<QPair<QObject *, QMouseEvent>> Renderer::pendingPickingEvents() const { return m_pickEventFilter->pendingMouseEvents(); } diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index 2654b3b61..b5c8d2c4c 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -260,7 +260,7 @@ public: inline RenderStateSet *defaultRenderState() const { return m_defaultRenderStateSet; } - QList<QMouseEvent> pendingPickingEvents() const; + QList<QPair<QObject*, QMouseEvent>> pendingPickingEvents() const; QList<QKeyEvent> pendingKeyEvents() const; void addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId); diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index da3d551e6..9e8177c0d 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -753,14 +753,19 @@ void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, c // ShaderData/Buffers would be handled as UBO/SSBO and would therefore // not be in the default uniform block if (value.valueType() == UniformValue::NodeId) { - const Qt3DCore::QNodeId texId = *value.constData<Qt3DCore::QNodeId>(); - const Texture *tex = m_manager->textureManager()->lookupResource(texId); - if (tex != nullptr) { - uniformPack.setTexture(nameId, texId); - UniformValue::Texture textureValue; - textureValue.nodeId = texId; - uniformPack.setUniform(nameId, UniformValue(textureValue)); + const Qt3DCore::QNodeId *nodeIds = value.constData<Qt3DCore::QNodeId>(); + + const int uniformArraySize = value.byteSize() / sizeof(Qt3DCore::QNodeId); + for (int i = 0; i < uniformArraySize; ++i) { + const Qt3DCore::QNodeId texId = nodeIds[i]; + const Texture *tex = m_manager->textureManager()->lookupResource(texId); + if (tex != nullptr) + uniformPack.setTexture(nameId, i, texId); } + + UniformValue textureValue(uniformArraySize * sizeof(int), UniformValue::TextureValue); + std::fill(textureValue.data<int>(), textureValue.data<int>() + uniformArraySize, -1); + uniformPack.setUniform(nameId, textureValue); } else { uniformPack.setUniform(nameId, value); } diff --git a/src/render/backend/shaderparameterpack.cpp b/src/render/backend/shaderparameterpack.cpp index 01a977aee..f78e45a5e 100644 --- a/src/render/backend/shaderparameterpack.cpp +++ b/src/render/backend/shaderparameterpack.cpp @@ -65,17 +65,17 @@ void ShaderParameterPack::setUniform(const int glslNameId, const UniformValue &v m_uniforms.insert(glslNameId, val); } -void ShaderParameterPack::setTexture(const int glslNameId, Qt3DCore::QNodeId texId) +void ShaderParameterPack::setTexture(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId texId) { for (int t=0; t<m_textures.size(); ++t) { - if (m_textures[t].glslNameId != glslNameId) + if (m_textures[t].glslNameId != glslNameId || m_textures[t].uniformArrayIndex != uniformArrayIndex) continue; m_textures[t].texId = texId; return; } - m_textures.append(NamedTexture(glslNameId, texId)); + m_textures.append(NamedTexture(glslNameId, texId, uniformArrayIndex)); } // Contains Uniform Block Index and QNodeId of the ShaderData (UBO) diff --git a/src/render/backend/shaderparameterpack_p.h b/src/render/backend/shaderparameterpack_p.h index c0ab05e57..abd63a187 100644 --- a/src/render/backend/shaderparameterpack_p.h +++ b/src/render/backend/shaderparameterpack_p.h @@ -96,7 +96,7 @@ public: ~ShaderParameterPack(); void setUniform(const int glslNameId, const UniformValue &val); - void setTexture(const int glslNameId, Qt3DCore::QNodeId id); + void setTexture(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId id); void setUniformBuffer(BlockToUBO blockToUBO); void setShaderStorageBuffer(BlockToSSBO blockToSSBO); void setSubmissionUniform(const ShaderUniform &uniform); @@ -108,13 +108,15 @@ public: struct NamedTexture { NamedTexture() {} - NamedTexture(const int nm, Qt3DCore::QNodeId t) - : glslNameId(nm) - , texId(t) + NamedTexture(const int glslNameId, Qt3DCore::QNodeId texId, int uniformArrayIndex) + : glslNameId(glslNameId) + , texId(texId) + , uniformArrayIndex(uniformArrayIndex) { } int glslNameId; Qt3DCore::QNodeId texId; + int uniformArrayIndex; }; inline QVector<NamedTexture> textures() const { return m_textures; } diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp index 4a05d8f19..87ba7bde9 100644 --- a/src/render/backend/trianglesvisitor.cpp +++ b/src/render/backend/trianglesvisitor.cpp @@ -85,8 +85,8 @@ void traverseTrianglesIndexed(index *indices, TrianglesVisitor* visitor) { uint i = 0; - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize; uint ndx[3]; Vector3D abc[3]; @@ -111,8 +111,8 @@ void traverseTriangles(vertex *vertices, { uint i = 0; - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize; uint ndx[3]; Vector3D abc[3]; @@ -147,8 +147,8 @@ void traverseTriangleStripIndexed(index *indices, TrianglesVisitor* visitor) { uint i = 0; - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize; uint ndx[3]; Vector3D abc[3]; @@ -178,8 +178,8 @@ void traverseTriangleStrip(vertex *vertices, { uint i = 0; - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize; uint ndx[3]; Vector3D abc[3]; @@ -204,8 +204,8 @@ void traverseTriangleFanIndexed(index *indices, const BufferInfo &vertexInfo, TrianglesVisitor* visitor) { - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize; uint ndx[3]; Vector3D abc[3]; @@ -234,8 +234,8 @@ void traverseTriangleFan(vertex *vertices, const BufferInfo &vertexInfo, TrianglesVisitor* visitor) { - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize; uint ndx[3]; Vector3D abc[3]; @@ -268,8 +268,8 @@ void traverseTriangleAdjacencyIndexed(index *indices, TrianglesVisitor* visitor) { uint i = 0; - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize; uint ndx[3]; Vector3D abc[3]; @@ -294,8 +294,8 @@ void traverseTriangleAdjacency(Vertex *vertices, { uint i = 0; - const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex); const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(Vertex) : maxVerticesDataSize; uint ndx[3]; Vector3D abc[3]; @@ -315,7 +315,7 @@ void traverseTriangleAdjacency(Vertex *vertices, template<typename Coordinate> Vector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint index) { - const uint stride = info.byteStride / sizeof(Coordinate); + const uint stride = info.byteStride ? info.byteStride / sizeof(Coordinate) : info.dataSize; Vector4D ret(0, 0, 0, 1.0f); coordinates += stride * index; for (uint e = 0; e < info.dataSize; ++e) diff --git a/src/render/backend/uniform.cpp b/src/render/backend/uniform.cpp index aedba5375..41ee24967 100644 --- a/src/render/backend/uniform.cpp +++ b/src/render/backend/uniform.cpp @@ -56,10 +56,12 @@ int byteSizeForMetaType(int type) { if (type == qMatrix4x4TypeId) return sizeof(Matrix4x4); - if (type == qVector3DTypeId) + if (type == qVector3DTypeId) return sizeof(Vector3D); - if (type == qVector4DTypeId) + if (type == qVector4DTypeId) return sizeof(Vector4D); + if (type == qNodeIdTypeId) + return sizeof(Qt3DCore::QNodeId); switch (type) { case QMetaType::Bool: @@ -230,6 +232,11 @@ UniformValue UniformValue::fromVariant(const QVariant &variant) break; const int listEntryType = variants.first().userType(); + + // array of textures + if (listEntryType == qNodeIdTypeId) + v.m_valueType = NodeId; + const int stride = byteSizeForMetaType(listEntryType) / sizeof(float); // Resize v.m_data v.m_data.resize(stride * variants.size()); diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h index 213cf2606..e31aaa609 100644 --- a/src/render/backend/uniform_p.h +++ b/src/render/backend/uniform_p.h @@ -114,11 +114,6 @@ public: BufferValue }; - struct Texture { - int textureId = 0; // Set first so that glUniform1iv will work - Qt3DCore::QNodeId nodeId; - }; - // UniformValue implicitely converts doubles to floats to ensure // correct rendering behavior for the cases where Qt3D parameters created from // a double or QVariant(double) are used to fill uniform values that in reality @@ -177,6 +172,13 @@ public: } } + // Reserve data to be filled in later + UniformValue(int byteSize, ValueType valueType) + : m_data(byteSize / sizeof(float)) + , m_valueType(valueType) + { + } + // For nodes which will later be replaced by a Texture or Buffer UniformValue(Qt3DCore::QNodeId id) : UniformValue() @@ -185,14 +187,6 @@ public: memcpy(m_data.data(), &id, sizeof(Qt3DCore::QNodeId)); } - // For textures - UniformValue(UniformValue::Texture t) - : UniformValue() - { - m_valueType = TextureValue; - memcpy(m_data.data(), &t, sizeof(Texture)); - } - ValueType valueType() const { return m_valueType; } UniformType storedType() const { return m_storedType; } diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index 298f6bf91..5c3128f30 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -499,14 +499,14 @@ void GraphicsContext::introspectShaderInterface(Shader *shader, QOpenGLShaderPro void GraphicsContext::loadShader(Shader *shader, ShaderManager *manager) { - QOpenGLShaderProgram *shaderProgram = m_shaderCache.getShaderProgramAndAddRef(shader->dna(), shader->peerId()); - if (!shaderProgram) { + bool wasPresent = false; + QOpenGLShaderProgram *shaderProgram = m_shaderCache.getShaderProgramAndAddRef(shader->dna(), shader->peerId(), &wasPresent); + if (!shaderProgram && !wasPresent) { // No matching QOpenGLShader in the cache so create one shaderProgram = createShaderProgram(shader); - // Store in cache - if (shaderProgram) - m_shaderCache.insert(shader->dna(), shader->peerId(), shaderProgram); + // Store in cache (even when failed and shaderProgram is null) + m_shaderCache.insert(shader->dna(), shader->peerId(), shaderProgram); } // Ensure the Shader node knows about the program interface @@ -1213,7 +1213,7 @@ bool GraphicsContext::setParameters(ShaderParameterPack ¶meterPack) UniformValue &texUniform = uniformValues[namedTex.glslNameId]; Q_ASSERT(texUniform.valueType() == UniformValue::TextureValue); const int texUnit = activateTexture(TextureScopeMaterial, t); - texUniform.data<UniformValue::Texture>()->textureId = texUnit; + texUniform.data<int>()[namedTex.uniformArrayIndex] = texUnit; // if the texture data from generators may not be available yet, // make sure that the next frame is rendered if (texUnit == -1) @@ -1263,11 +1263,10 @@ bool GraphicsContext::setParameters(ShaderParameterPack ¶meterPack) for (const ShaderUniform &uniform : activeUniforms) { // We can use [] as we are sure the the uniform wouldn't // be un activeUniforms if there wasn't a matching value - const auto &v = values[uniform.m_nameId]; + const UniformValue &v = values[uniform.m_nameId]; // skip invalid textures - if (v.valueType() == UniformValue::TextureValue && - v.constData<UniformValue::Texture>()->textureId == -1) + if (v.valueType() == UniformValue::TextureValue && *v.constData<int>() == -1) continue; applyUniform(uniform, v); diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp index 7504b4ebd..aaee51e16 100644 --- a/src/render/jobs/calcboundingvolumejob.cpp +++ b/src/render/jobs/calcboundingvolumejob.cpp @@ -81,10 +81,10 @@ public: const Sphere& result() { return m_volume; } - bool apply(Qt3DRender::Render::Attribute *positionAttribute) + bool apply(Qt3DRender::Render::Attribute *positionAttribute, Qt3DRender::Render::Attribute *indexAttribute, int drawVertexCount) { FindExtremePoints findExtremePoints(m_manager); - if (!findExtremePoints.apply(positionAttribute)) + if (!findExtremePoints.apply(positionAttribute, indexAttribute, drawVertexCount)) return false; // Calculate squared distance for the pairs of points @@ -109,7 +109,7 @@ public: m_volume.setRadius((q - c).length()); ExpandSphere expandSphere(m_manager, m_volume); - if (!expandSphere.apply(positionAttribute)) + if (!expandSphere.apply(positionAttribute, indexAttribute, drawVertexCount)) return false; return true; @@ -191,10 +191,12 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node) return; GeometryRenderer *gRenderer = node->renderComponent<GeometryRenderer>(); - if (gRenderer) { + if (gRenderer && gRenderer->primitiveType() != QGeometryRenderer::Patches) { Geometry *geom = manager->lookupResource<Geometry, GeometryManager>(gRenderer->geometryId()); if (geom) { + int drawVertexCount = gRenderer->vertexCount(); // may be 0, gets changed below if so + Qt3DRender::Render::Attribute *positionAttribute = manager->lookupResource<Attribute, AttributeManager>(geom->boundingPositionAttribute()); // Use the default position attribute if attribute is null @@ -212,29 +214,60 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node) || positionAttribute->attributeType() != QAttribute::VertexAttribute || positionAttribute->vertexBaseType() != QAttribute::Float || positionAttribute->vertexSize() < 3) { - qWarning() << "QGeometry::boundingVolumePositionAttribute position Attribute not suited for bounding volume computation"; + qWarning("calculateLocalBoundingVolume: Position attribute not suited for bounding volume computation"); return; } Buffer *buf = manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId()); // No point in continuing if the positionAttribute doesn't have a suitable buffer if (!buf) { - qWarning() << "ObjectPicker position Attribute not referencing a valid buffer"; + qWarning("calculateLocalBoundingVolume: Position attribute not referencing a valid buffer"); return; } + // Check if there is an index attribute. + Qt3DRender::Render::Attribute *indexAttribute = nullptr; + Buffer *indexBuf = nullptr; + const QVector<Qt3DCore::QNodeId> attributes = geom->attributes(); + + for (Qt3DCore::QNodeId attrNodeId : attributes) { + Qt3DRender::Render::Attribute *attr = manager->lookupResource<Attribute, AttributeManager>(attrNodeId); + if (attr && attr->attributeType() == Qt3DRender::QAttribute::IndexAttribute) { + indexBuf = manager->lookupResource<Buffer, BufferManager>(attr->bufferId()); + if (indexBuf) { + indexAttribute = attr; + + if (!drawVertexCount) + drawVertexCount = indexAttribute->count(); + + if (indexAttribute->vertexBaseType() != QAttribute::UnsignedShort + && indexAttribute->vertexBaseType() != QAttribute::UnsignedInt) + { + qWarning("calculateLocalBoundingVolume: Unsupported index attribute type"); + return; + } + + break; + } + } + } + + if (!indexAttribute && !drawVertexCount) + drawVertexCount = positionAttribute->count(); + // Buf will be set to not dirty once it's loaded // in a job executed after this one // We need to recompute the bounding volume // If anything in the GeometryRenderer has changed - if (buf->isDirty() || - node->isBoundingVolumeDirty() || - positionAttribute->isDirty() || - geom->isDirty() || - gRenderer->isDirty()) { - + if (buf->isDirty() + || node->isBoundingVolumeDirty() + || positionAttribute->isDirty() + || geom->isDirty() + || gRenderer->isDirty() + || (indexAttribute && indexAttribute->isDirty()) + || (indexBuf && indexBuf->isDirty())) { BoundingVolumeCalculator reader(manager); - if (reader.apply(positionAttribute)) { + if (reader.apply(positionAttribute, indexAttribute, drawVertexCount)) { node->localBoundingVolume()->setCenter(reader.result().center()); node->localBoundingVolume()->setRadius(reader.result().radius()); node->unsetBoundingVolumeDirty(); diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp index 902c048e6..23a553084 100644 --- a/src/render/jobs/pickboundingvolumejob.cpp +++ b/src/render/jobs/pickboundingvolumejob.cpp @@ -54,6 +54,10 @@ #include <Qt3DRender/private/qpickevent_p.h> #include <Qt3DRender/private/pickboundingvolumeutils_p.h> +#include <QSurface> +#include <QWindow> +#include <QOffscreenSurface> + QT_BEGIN_NAMESPACE namespace Qt3DRender { @@ -119,7 +123,7 @@ void PickBoundingVolumeJob::setRoot(Entity *root) m_node = root; } -void PickBoundingVolumeJob::setMouseEvents(const QList<QMouseEvent> &pendingEvents) +void PickBoundingVolumeJob::setMouseEvents(const QList<QPair<QObject*, QMouseEvent>> &pendingEvents) { m_pendingMouseEvents = pendingEvents; } @@ -185,8 +189,8 @@ bool PickBoundingVolumeJob::runHelper() bool hasMoveEvent = false; bool hasOtherEvent = false; // Quickly look which types of events we've got - for (const QMouseEvent &event : mouseEvents) { - const bool isMove = (event.type() == QEvent::MouseMove); + for (const auto &event : mouseEvents) { + const bool isMove = (event.second.type() == QEvent::MouseMove); hasMoveEvent |= isMove; hasOtherEvent |= !isMove; } @@ -214,10 +218,10 @@ bool PickBoundingVolumeJob::runHelper() PickingUtils::ViewportCameraAreaGatherer vcaGatherer; // TO DO: We could cache this and only gather when we know the FrameGraph tree has changed - const QVector<PickingUtils::ViewportCameraAreaTriplet> vcaTriplets = vcaGatherer.gather(m_frameGraphRoot); + const QVector<PickingUtils::ViewportCameraAreaDetails> vcaDetails = vcaGatherer.gather(m_frameGraphRoot); // If we have no viewport / camera or area, return early - if (vcaTriplets.empty()) + if (vcaDetails.empty()) return false; // TO DO: @@ -236,19 +240,21 @@ bool PickBoundingVolumeJob::runHelper() const float pickWorldSpaceTolerance = m_renderSettings->pickWorldSpaceTolerance(); // For each mouse event - for (const QMouseEvent &event : mouseEvents) { + for (const auto &event : mouseEvents) { m_hoveredPickersToClear = m_hoveredPickers; QPickEvent::Buttons eventButton = QPickEvent::NoButton; int eventButtons = 0; int eventModifiers = QPickEvent::NoModifier; - setEventButtonAndModifiers(event, eventButton, eventButtons, eventModifiers); + setEventButtonAndModifiers(event.second, eventButton, eventButtons, eventModifiers); - // For each triplet of Viewport / Camera and Area - for (const PickingUtils::ViewportCameraAreaTriplet &vca : vcaTriplets) { + // For each Viewport / Camera and Area entry + for (const PickingUtils::ViewportCameraAreaDetails &vca : vcaDetails) { PickingUtils::HitList sphereHits; - QRay3D ray = rayForViewportAndCamera(vca.area, event.pos(), vca.viewport, vca.cameraId); + QRay3D ray = rayForViewportAndCamera(vca, event.first, event.second); + if (!ray.isValid()) + continue; PickingUtils::HierarchicalEntityPicker entityPicker(ray); if (entityPicker.collectHits(m_node)) { @@ -285,7 +291,7 @@ bool PickBoundingVolumeJob::runHelper() } // Dispatch events based on hit results - dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers, allHitsRequested); + dispatchPickEvents(event.second, sphereHits, eventButton, eventButtons, eventModifiers, allHitsRequested); } } @@ -479,7 +485,7 @@ void PickBoundingVolumeJob::viewMatrixForCamera(Qt3DCore::QNodeId cameraId, if (camNode != nullptr && (lens = camNode->renderComponent<CameraLens>()) != nullptr && lens->isEnabled()) { - viewMatrix = *camNode->worldTransform(); + viewMatrix = lens->viewMatrix(*camNode->worldTransform()); projectionMatrix = lens->projection(); } } @@ -497,18 +503,38 @@ QRect PickBoundingVolumeJob::windowViewport(const QSize &area, const QRectF &rel return relativeViewport.toRect(); } -RayCasting::QRay3D PickBoundingVolumeJob::rayForViewportAndCamera(const QSize &area, - const QPoint &pos, - const QRectF &relativeViewport, - const Qt3DCore::QNodeId cameraId) const +RayCasting::QRay3D PickBoundingVolumeJob::rayForViewportAndCamera(const PickingUtils::ViewportCameraAreaDetails &vca, + QObject *eventSource, + const QMouseEvent &event) const { + static RayCasting::QRay3D invalidRay({}, {}, 0.f); + Matrix4x4 viewMatrix; Matrix4x4 projectionMatrix; - viewMatrixForCamera(cameraId, viewMatrix, projectionMatrix); - const QRect viewport = windowViewport(area, relativeViewport); + viewMatrixForCamera(vca.cameraId, viewMatrix, projectionMatrix); + const QRect viewport = windowViewport(vca.area, vca.viewport); + const QPoint pos = event.pos(); + + if (vca.area.isValid() && !viewport.contains(pos)) + return invalidRay; + if (vca.surface) { + QSurface *surface = nullptr; + if (eventSource) { + QWindow *window = qobject_cast<QWindow *>(eventSource); + if (window) { + surface = static_cast<QSurface *>(window); + } else { + QOffscreenSurface *offscreen = qobject_cast<QOffscreenSurface *>(eventSource); + if (offscreen) + surface = static_cast<QSurface *>(offscreen); + } + } + if (surface && vca.surface != surface) + return invalidRay; + } // In GL the y is inverted compared to Qt - const QPoint glCorrectPos = QPoint(pos.x(), area.isValid() ? area.height() - pos.y() : pos.y()); + const QPoint glCorrectPos = QPoint(pos.x(), vca.area.isValid() ? vca.area.height() - pos.y() : pos.y()); const auto ray = intersectionRay(glCorrectPos, viewMatrix, projectionMatrix, viewport); return ray; } diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h index 5d4f63f77..016d1ba0b 100644 --- a/src/render/jobs/pickboundingvolumejob_p.h +++ b/src/render/jobs/pickboundingvolumejob_p.h @@ -56,6 +56,7 @@ #include <Qt3DRender/private/handle_types_p.h> #include <Qt3DRender/private/qboundingvolumeprovider_p.h> #include <Qt3DRender/private/qcollisionqueryresult_p.h> +#include <Qt3DRender/private/pickboundingvolumeutils_p.h> #include <Qt3DRender/qpickevent.h> #include <QMouseEvent> #include <QKeyEvent> @@ -85,7 +86,7 @@ public: PickBoundingVolumeJob(); void setRoot(Entity *root); - void setMouseEvents(const QList<QMouseEvent> &pendingEvents); + void setMouseEvents(const QList<QPair<QObject*, QMouseEvent>> &pendingEvents); void setKeyEvents(const QList<QKeyEvent> &pendingEvents); void setFrameGraphRoot(FrameGraphNode *frameGraphRoot); void setRenderSettings(RenderSettings *settings); @@ -117,7 +118,7 @@ private: Entity *m_node; FrameGraphNode *m_frameGraphRoot; RenderSettings *m_renderSettings; - QList<QMouseEvent> m_pendingMouseEvents; + QList<QPair<QObject*, QMouseEvent>> m_pendingMouseEvents; bool m_pickersDirty; bool m_oneEnabledAtLeast; bool m_oneHoverAtLeast; @@ -128,10 +129,9 @@ private: Matrix4x4 &viewMatrix, Matrix4x4 &projectionMatrix) const; QRect windowViewport(const QSize &area, const QRectF &relativeViewport) const; - RayCasting::QRay3D rayForViewportAndCamera(const QSize &area, - const QPoint &pos, - const QRectF &relativeViewport, - const Qt3DCore::QNodeId cameraId) const; + RayCasting::QRay3D rayForViewportAndCamera(const PickingUtils::ViewportCameraAreaDetails &vca, + QObject *eventSource, + const QMouseEvent &event) const; void clearPreviouslyHoveredPickers(); HObjectPicker m_currentPicker; QVector<HObjectPicker> m_hoveredPickers; diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp index ae80b0a23..fb45d563f 100644 --- a/src/render/jobs/pickboundingvolumeutils.cpp +++ b/src/render/jobs/pickboundingvolumeutils.cpp @@ -72,9 +72,9 @@ void ViewportCameraAreaGatherer::visit(FrameGraphNode *node) m_leaves.push_back(node); } -ViewportCameraAreaTriplet ViewportCameraAreaGatherer::gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const +ViewportCameraAreaDetails ViewportCameraAreaGatherer::gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const { - ViewportCameraAreaTriplet vca; + ViewportCameraAreaDetails vca; vca.viewport = QRectF(0.0f, 0.0f, 1.0f, 1.0f); while (node) { @@ -86,9 +86,12 @@ ViewportCameraAreaTriplet ViewportCameraAreaGatherer::gatherUpViewportCameraArea case FrameGraphNode::Viewport: vca.viewport = computeViewport(vca.viewport, static_cast<const ViewportNode *>(node)); break; - case FrameGraphNode::Surface: - vca.area = static_cast<const RenderSurfaceSelector *>(node)->renderTargetSize(); + case FrameGraphNode::Surface: { + auto selector = static_cast<const RenderSurfaceSelector *>(node); + vca.area = selector->renderTargetSize(); + vca.surface = selector->surface(); break; + } default: break; } @@ -98,29 +101,32 @@ ViewportCameraAreaTriplet ViewportCameraAreaGatherer::gatherUpViewportCameraArea return vca; } -QVector<ViewportCameraAreaTriplet> ViewportCameraAreaGatherer::gather(FrameGraphNode *root) +QVector<ViewportCameraAreaDetails> ViewportCameraAreaGatherer::gather(FrameGraphNode *root) { // Retrieve all leaves visit(root); - QVector<ViewportCameraAreaTriplet> vcaTriplets; + QVector<ViewportCameraAreaDetails> vcaTriplets; vcaTriplets.reserve(m_leaves.count()); // Find all viewport/camera pairs by traversing from leaf to root for (Render::FrameGraphNode *leaf : qAsConst(m_leaves)) { - ViewportCameraAreaTriplet vcaTriplet = gatherUpViewportCameraAreas(leaf); - if (!m_targetCamera.isNull() && vcaTriplet.cameraId != m_targetCamera) + ViewportCameraAreaDetails vcaDetails = gatherUpViewportCameraAreas(leaf); + if (!m_targetCamera.isNull() && vcaDetails.cameraId != m_targetCamera) continue; - if (!vcaTriplet.cameraId.isNull() && isUnique(vcaTriplets, vcaTriplet)) - vcaTriplets.push_back(vcaTriplet); + if (!vcaDetails.cameraId.isNull() && isUnique(vcaTriplets, vcaDetails)) + vcaTriplets.push_back(vcaDetails); } return vcaTriplets; } -bool ViewportCameraAreaGatherer::isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, - const ViewportCameraAreaTriplet &vca) const +bool ViewportCameraAreaGatherer::isUnique(const QVector<ViewportCameraAreaDetails> &vcaList, + const ViewportCameraAreaDetails &vca) const { - for (const ViewportCameraAreaTriplet &triplet : vcaTriplets) { - if (vca.cameraId == triplet.cameraId && vca.viewport == triplet.viewport && vca.area == triplet.area) + for (const ViewportCameraAreaDetails &listItem : vcaList) { + if (vca.cameraId == listItem.cameraId && + vca.viewport == listItem.viewport && + vca.surface == listItem.surface && + vca.area == listItem.area) return false; } return true; diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h index 6e2532ea5..9cd6a5bbc 100644 --- a/src/render/jobs/pickboundingvolumeutils_p.h +++ b/src/render/jobs/pickboundingvolumeutils_p.h @@ -58,6 +58,8 @@ QT_BEGIN_NAMESPACE +class QSurface; + namespace Qt3DRender { namespace RayCasting { class QAbstractCollisionQueryService; @@ -72,27 +74,28 @@ class NodeManagers; namespace PickingUtils { -struct Q_AUTOTEST_EXPORT ViewportCameraAreaTriplet +struct Q_AUTOTEST_EXPORT ViewportCameraAreaDetails { Qt3DCore::QNodeId cameraId; QRectF viewport; QSize area; + QSurface *surface = nullptr; }; -QT3D_DECLARE_TYPEINFO_3(Qt3DRender, Render, PickingUtils, ViewportCameraAreaTriplet, Q_PRIMITIVE_TYPE) +QT3D_DECLARE_TYPEINFO_3(Qt3DRender, Render, PickingUtils, ViewportCameraAreaDetails, Q_PRIMITIVE_TYPE) class Q_AUTOTEST_EXPORT ViewportCameraAreaGatherer { public: ViewportCameraAreaGatherer(const Qt3DCore::QNodeId &nodeId = Qt3DCore::QNodeId()) : m_targetCamera(nodeId) { } - QVector<ViewportCameraAreaTriplet> gather(FrameGraphNode *root); + QVector<ViewportCameraAreaDetails> gather(FrameGraphNode *root); private: Qt3DCore::QNodeId m_targetCamera; QVector<FrameGraphNode *> m_leaves; void visit(FrameGraphNode *node); - ViewportCameraAreaTriplet gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const; - bool isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, const ViewportCameraAreaTriplet &vca) const; + ViewportCameraAreaDetails gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const; + bool isUnique(const QVector<ViewportCameraAreaDetails> &vcaList, const ViewportCameraAreaDetails &vca) const; }; class Q_AUTOTEST_EXPORT EntityGatherer diff --git a/src/render/jobs/updatelevelofdetailjob.cpp b/src/render/jobs/updatelevelofdetailjob.cpp index ad9bee8e1..141d65c22 100644 --- a/src/render/jobs/updatelevelofdetailjob.cpp +++ b/src/render/jobs/updatelevelofdetailjob.cpp @@ -175,11 +175,11 @@ void UpdateLevelOfDetailJob::updateEntityLodByScreenArea(Entity *entity, LevelOf return; PickingUtils::ViewportCameraAreaGatherer vcaGatherer(lod->camera()); - const QVector<PickingUtils::ViewportCameraAreaTriplet> vcaTriplets = vcaGatherer.gather(m_frameGraphRoot); + const QVector<PickingUtils::ViewportCameraAreaDetails> vcaTriplets = vcaGatherer.gather(m_frameGraphRoot); if (vcaTriplets.isEmpty()) return; - const PickingUtils::ViewportCameraAreaTriplet &vca = vcaTriplets.front(); + const PickingUtils::ViewportCameraAreaDetails &vca = vcaTriplets.front(); const QVector<qreal> thresholds = lod->thresholds(); Sphere bv(Vector3D(lod->center()), lod->radius()); diff --git a/src/render/materialsystem/qparameter.cpp b/src/render/materialsystem/qparameter.cpp index b9bfa44e7..2b2dd29d5 100644 --- a/src/render/materialsystem/qparameter.cpp +++ b/src/render/materialsystem/qparameter.cpp @@ -179,13 +179,30 @@ QParameterPrivate::QParameterPrivate() { } +namespace { + +/*! \internal */ +inline QVariant toBackendValue(const QVariant &v) +{ + if (auto nodeValue = v.value<Qt3DCore::QNode*>()) + return QVariant::fromValue(nodeValue->id()); + return v; +} + +} // anonymous + void QParameterPrivate::setValue(const QVariant &v) { - Qt3DCore::QNode *nodeValue = v.value<Qt3DCore::QNode *>(); - if (nodeValue != nullptr) - m_backendValue = QVariant::fromValue(nodeValue->id()); - else - m_backendValue = v; + if (v.type() == QVariant::List) { + QSequentialIterable iterable = v.value<QSequentialIterable>(); + QVariantList variants; + variants.reserve(iterable.size()); + for (const auto &v : iterable) + variants.append(toBackendValue(v)); + m_backendValue = variants; + } else { + m_backendValue = toBackendValue(v); + } m_value = v; } diff --git a/src/render/materialsystem/shadercache.cpp b/src/render/materialsystem/shadercache.cpp index 4ddf26799..ce29622ad 100644 --- a/src/render/materialsystem/shadercache.cpp +++ b/src/render/materialsystem/shadercache.cpp @@ -62,18 +62,28 @@ ShaderCache::~ShaderCache() * * \return A pointer to the shader program if it is cached, nullptr otherwise */ -QOpenGLShaderProgram *ShaderCache::getShaderProgramAndAddRef(ProgramDNA dna, Qt3DCore::QNodeId shaderPeerId) +QOpenGLShaderProgram *ShaderCache::getShaderProgramAndAddRef(ProgramDNA dna, Qt3DCore::QNodeId shaderPeerId, bool *wasPresent) { - auto shaderProgram = m_programHash.value(dna, nullptr); - if (shaderProgram) { + auto shaderProgram = m_programHash.constFind(dna); + + // Some callers may wish to differentiate between a result of null due to + // not having anything in the cache and a result of null due to the cache + // containing a program the shaders of which failed to compile. + if (wasPresent) + *wasPresent = shaderProgram != m_programHash.constEnd(); + + if (shaderProgram != m_programHash.constEnd()) { // Ensure we store the fact that shaderPeerId references this shader QMutexLocker lock(&m_refsMutex); QVector<Qt3DCore::QNodeId> &programRefs = m_programRefs[dna]; auto it = std::lower_bound(programRefs.begin(), programRefs.end(), shaderPeerId); if (*it != shaderPeerId) programRefs.insert(it, shaderPeerId); + + return *shaderProgram; } - return shaderProgram; + + return nullptr; } /*! diff --git a/src/render/materialsystem/shadercache_p.h b/src/render/materialsystem/shadercache_p.h index 24a55876e..bda629ee5 100644 --- a/src/render/materialsystem/shadercache_p.h +++ b/src/render/materialsystem/shadercache_p.h @@ -71,7 +71,7 @@ class QT3DRENDERSHARED_PRIVATE_EXPORT ShaderCache public: ~ShaderCache(); - QOpenGLShaderProgram *getShaderProgramAndAddRef(ProgramDNA dna, Qt3DCore::QNodeId shaderPeerId); + QOpenGLShaderProgram *getShaderProgramAndAddRef(ProgramDNA dna, Qt3DCore::QNodeId shaderPeerId, bool *wasPresent = nullptr); void insert(ProgramDNA dna, Qt3DCore::QNodeId shaderPeerId, QOpenGLShaderProgram *program); void removeRef(ProgramDNA dna, Qt3DCore::QNodeId shaderPeerId); void purge(); diff --git a/src/render/picking/pickeventfilter.cpp b/src/render/picking/pickeventfilter.cpp index 297911e45..b10383c72 100644 --- a/src/render/picking/pickeventfilter.cpp +++ b/src/render/picking/pickeventfilter.cpp @@ -62,10 +62,10 @@ PickEventFilter::~PickEventFilter() Called from a worker thread in the thread pool so be sure to mutex protect the data. */ -QList<QMouseEvent> PickEventFilter::pendingMouseEvents() +QList<QPair<QObject *, QMouseEvent> > PickEventFilter::pendingMouseEvents() { QMutexLocker locker(&m_mutex); - QList<QMouseEvent> pendingEvents(m_pendingMouseEvents); + QList<QPair<QObject*, QMouseEvent>> pendingEvents(m_pendingMouseEvents); m_pendingMouseEvents.clear(); return pendingEvents; } @@ -90,14 +90,14 @@ bool PickEventFilter::eventFilter(QObject *obj, QEvent *e) case QEvent::MouseButtonRelease: case QEvent::MouseMove: { QMutexLocker locker(&m_mutex); - m_pendingMouseEvents.push_back(QMouseEvent(*static_cast<QMouseEvent *>(e))); + m_pendingMouseEvents.push_back({obj, QMouseEvent(*static_cast<QMouseEvent *>(e))}); } break; case QEvent::HoverMove: { QMutexLocker locker(&m_mutex); QHoverEvent *he = static_cast<QHoverEvent *>(e); - m_pendingMouseEvents.push_back(QMouseEvent(QEvent::MouseMove, + m_pendingMouseEvents.push_back({obj, QMouseEvent(QEvent::MouseMove, he->pos(), Qt::NoButton, Qt::NoButton, - he->modifiers())); + he->modifiers())}); } break; case QEvent::KeyPress: case QEvent::KeyRelease: { diff --git a/src/render/picking/pickeventfilter_p.h b/src/render/picking/pickeventfilter_p.h index fc4b00ddc..da41598b3 100644 --- a/src/render/picking/pickeventfilter_p.h +++ b/src/render/picking/pickeventfilter_p.h @@ -69,14 +69,14 @@ public: explicit PickEventFilter(QObject *parent = nullptr); ~PickEventFilter(); - QList<QMouseEvent> pendingMouseEvents(); + QList<QPair<QObject*, QMouseEvent>> pendingMouseEvents(); QList<QKeyEvent> pendingKeyEvents(); protected: bool eventFilter(QObject *obj, QEvent *e) Q_DECL_FINAL; private: - QList<QMouseEvent> m_pendingMouseEvents; + QList<QPair<QObject*, QMouseEvent>> m_pendingMouseEvents; QList<QKeyEvent> m_pendingKeyEvents; QMutex m_mutex; }; diff --git a/src/render/raycasting/qray3d_p.h b/src/render/raycasting/qray3d_p.h index c5e2be078..8b7852cc3 100644 --- a/src/render/raycasting/qray3d_p.h +++ b/src/render/raycasting/qray3d_p.h @@ -93,6 +93,8 @@ public: bool operator==(const QRay3D &other) const; bool operator!=(const QRay3D &other) const; + bool isValid() const { return !m_direction.isNull() && !qFuzzyIsNull(m_distance); } + private: Vector3D m_origin; Vector3D m_direction; |