summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Harmer <sean.harmer@kdab.com>2018-02-05 13:01:09 +0000
committerSean Harmer <sean.harmer@kdab.com>2018-02-05 15:42:29 +0000
commit0403ee45736241aa621eb3d38880a4fff571fd96 (patch)
tree94650145a3b7e2517dfcf29d33f97859933b518d
parent04afcf1cb9e79697360baa01a97a26815237eba1 (diff)
parentceae743678d41a58154612781e896c04c87a8c4f (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
-rw-r--r--src/core/changes/qcomponentaddedchange.cpp12
-rw-r--r--src/core/changes/qcomponentaddedchange.h2
-rw-r--r--src/core/changes/qcomponentremovedchange.cpp13
-rw-r--r--src/core/changes/qcomponentremovedchange.h2
-rw-r--r--src/core/changes/qpropertynodeaddedchange.cpp10
-rw-r--r--src/core/nodes/qcomponent.cpp4
-rw-r--r--src/core/nodes/qnode.cpp64
-rw-r--r--src/core/nodes/qnode_p.h4
-rw-r--r--src/doc/src/qt3danimation-module.qdoc2
-rw-r--r--src/doc/src/qt3dextras-module.qdoc2
-rw-r--r--src/plugins/sceneparsers/assimp/assimpimporter.cpp19
-rw-r--r--src/plugins/sceneparsers/assimp/assimpimporter.h1
-rw-r--r--src/render/backend/buffervisitor_p.h129
-rw-r--r--src/render/backend/renderer.cpp2
-rw-r--r--src/render/backend/renderer_p.h2
-rw-r--r--src/render/backend/renderview.cpp19
-rw-r--r--src/render/backend/shaderparameterpack.cpp6
-rw-r--r--src/render/backend/shaderparameterpack_p.h10
-rw-r--r--src/render/backend/trianglesvisitor.cpp18
-rw-r--r--src/render/backend/uniform.cpp11
-rw-r--r--src/render/backend/uniform_p.h20
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp17
-rw-r--r--src/render/jobs/calcboundingvolumejob.cpp59
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp64
-rw-r--r--src/render/jobs/pickboundingvolumejob_p.h12
-rw-r--r--src/render/jobs/pickboundingvolumeutils.cpp34
-rw-r--r--src/render/jobs/pickboundingvolumeutils_p.h13
-rw-r--r--src/render/jobs/updatelevelofdetailjob.cpp4
-rw-r--r--src/render/materialsystem/qparameter.cpp27
-rw-r--r--src/render/materialsystem/shadercache.cpp18
-rw-r--r--src/render/materialsystem/shadercache_p.h2
-rw-r--r--src/render/picking/pickeventfilter.cpp10
-rw-r--r--src/render/picking/pickeventfilter_p.h4
-rw-r--r--src/render/raycasting/qray3d_p.h2
-rw-r--r--tests/auto/core/nodes/tst_nodes.cpp117
-rw-r--r--tests/auto/render/boundingsphere/tst_boundingsphere.cpp228
-rw-r--r--tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.qrc2
-rw-r--r--tests/auto/render/pickboundingvolumejob/testscene_cameraposition.qml115
-rw-r--r--tests/auto/render/pickboundingvolumejob/testscene_viewports.qml158
-rw-r--r--tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp259
-rw-r--r--tests/auto/render/shadercache/tst_shadercache.cpp13
-rw-r--r--tests/auto/render/trianglevisitor/tst_trianglevisitor.cpp2
42 files changed, 1260 insertions, 252 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 &parameterPack)
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 &parameterPack)
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;
diff --git a/tests/auto/core/nodes/tst_nodes.cpp b/tests/auto/core/nodes/tst_nodes.cpp
index 49618821c..4998e07d7 100644
--- a/tests/auto/core/nodes/tst_nodes.cpp
+++ b/tests/auto/core/nodes/tst_nodes.cpp
@@ -81,6 +81,7 @@ private slots:
void checkConstructionSetParentMix(); // QTBUG-60612
void checkConstructionWithParent();
+ void checkConstructionAsListElement();
void appendingComponentToEntity();
void appendingParentlessComponentToEntity();
@@ -240,6 +241,43 @@ public slots:
emit nodePropertyChanged(node);
}
+ void addAttribute(MyQNode *attribute)
+ {
+ Qt3DCore::QNodePrivate *d = Qt3DCore::QNodePrivate::get(this);
+ if (!m_attributes.contains(attribute)) {
+ m_attributes.append(attribute);
+
+ // Ensures proper bookkeeping
+ d->registerDestructionHelper(attribute, &MyQNode::removeAttribute, m_attributes);
+
+ // We need to add it as a child of the current node if it has been declared inline
+ // Or not previously added as a child of the current node so that
+ // 1) The backend gets notified about it's creation
+ // 2) When the current node is destroyed, it gets destroyed as well
+ if (!attribute->parent())
+ attribute->setParent(this);
+
+ if (d->m_changeArbiter != nullptr) {
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(id(), attribute);
+ change->setPropertyName("attribute");
+ d->notifyObservers(change);
+ }
+ }
+ }
+
+ void removeAttribute(MyQNode *attribute)
+ {
+ Qt3DCore::QNodePrivate *d = Qt3DCore::QNodePrivate::get(this);
+ if (d->m_changeArbiter != nullptr) {
+ const auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(id(), attribute);
+ change->setPropertyName("attribute");
+ d->notifyObservers(change);
+ }
+ m_attributes.removeOne(attribute);
+ // Remove bookkeeping connection
+ d->unregisterDestructionHelper(attribute);
+ }
+
signals:
void customPropertyChanged();
void nodePropertyChanged(MyQNode *node);
@@ -247,6 +285,7 @@ signals:
protected:
QString m_customProperty;
MyQNode *m_nodeProperty;
+ QVector<MyQNode *> m_attributes;
};
class MyQEntity : public Qt3DCore::QEntity
@@ -921,6 +960,50 @@ void tst_Nodes::checkConstructionWithParent()
QCOMPARE(propertyEvent->value().value<Qt3DCore::QNodeId>(), node->id());
}
+void tst_Nodes::checkConstructionAsListElement()
+{
+ // GIVEN
+ ObserverSpy spy;
+ Qt3DCore::QScene scene;
+ QScopedPointer<MyQNode> root(new MyQNode());
+
+ // WHEN
+ root->setArbiterAndScene(&spy, &scene);
+ root->setSimulateBackendCreated(true);
+
+ // THEN
+ QVERIFY(Qt3DCore::QNodePrivate::get(root.data())->scene() != nullptr);
+
+ // WHEN we create a child and then set it as a Node* property
+ auto *node = new MyQNode(root.data());
+ root->addAttribute(node);
+
+ // THEN we should get one creation change, one child added change
+ // and one property change event, in that order.
+ QCoreApplication::processEvents();
+
+ QCOMPARE(root->children().count(), 1);
+ QCOMPARE(spy.events.size(), 3); // 1 creation change, 1 child added change, 1 property change
+
+ // Ensure first event is child node's creation change
+ const auto creationEvent = spy.events.takeFirst().change().dynamicCast<Qt3DCore::QNodeCreatedChangeBase>();
+ QVERIFY(!creationEvent.isNull());
+ QCOMPARE(creationEvent->subjectId(), node->id());
+
+ const auto newChildEvent = spy.events.takeFirst().change().dynamicCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QVERIFY(!newChildEvent.isNull());
+ QCOMPARE(newChildEvent->subjectId(), root->id());
+ QCOMPARE(newChildEvent->propertyName(), "children");
+ QCOMPARE(newChildEvent->addedNodeId(), node->id());
+
+ // Ensure second and last event is property set change
+ const auto propertyEvent = spy.events.takeFirst().change().dynamicCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QVERIFY(!propertyEvent.isNull());
+ QCOMPARE(propertyEvent->subjectId(), root->id());
+ QCOMPARE(propertyEvent->propertyName(), "attribute");
+ QCOMPARE(newChildEvent->addedNodeId(), node->id());
+}
+
void tst_Nodes::appendingParentlessComponentToEntity()
{
// GIVEN
@@ -958,15 +1041,22 @@ void tst_Nodes::appendingParentlessComponentToEntity()
// return early in such a case.
// Check that we received ComponentAdded
- for (const auto event: { entitySpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentAddedChange>(),
- componentSpy.events.takeLast().change().dynamicCast<Qt3DCore::QComponentAddedChange>() })
{
+ const auto event = entitySpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentAddedChange>();
QCOMPARE(event->type(), Qt3DCore::ComponentAdded);
QCOMPARE(event->subjectId(), entity->id());
QCOMPARE(event->entityId(), entity->id());
QCOMPARE(event->componentId(), comp->id());
QCOMPARE(event->componentMetaObject(), comp->metaObject());
}
+ {
+ const auto event = componentSpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentAddedChange>();
+ QCOMPARE(event->type(), Qt3DCore::ComponentAdded);
+ QCOMPARE(event->subjectId(), comp->id());
+ QCOMPARE(event->entityId(), entity->id());
+ QCOMPARE(event->componentId(), comp->id());
+ QCOMPARE(event->componentMetaObject(), comp->metaObject());
+ }
}
}
@@ -997,15 +1087,22 @@ void tst_Nodes::appendingComponentToEntity()
QVERIFY(comp->parentNode() == entity.data());
QCOMPARE(entitySpy.events.size(), 1);
QVERIFY(entitySpy.events.first().wasLocked());
- for (const auto event: { entitySpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentAddedChange>(),
- componentSpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentAddedChange>() })
{
+ const auto event = entitySpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentAddedChange>();
QCOMPARE(event->type(), Qt3DCore::ComponentAdded);
QCOMPARE(event->subjectId(), entity->id());
QCOMPARE(event->entityId(), entity->id());
QCOMPARE(event->componentId(), comp->id());
QCOMPARE(event->componentMetaObject(), comp->metaObject());
}
+ {
+ const auto event = componentSpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentAddedChange>();
+ QCOMPARE(event->type(), Qt3DCore::ComponentAdded);
+ QCOMPARE(event->subjectId(), comp->id());
+ QCOMPARE(event->entityId(), entity->id());
+ QCOMPARE(event->componentId(), comp->id());
+ QCOMPARE(event->componentMetaObject(), comp->metaObject());
+ }
}
}
@@ -1040,14 +1137,22 @@ void tst_Nodes::removingComponentFromEntity()
QCOMPARE(entitySpy.events.size(), 1);
QVERIFY(entitySpy.events.first().wasLocked());
QCOMPARE(componentSpy.events.size(), 1);
- for (const auto event: { entitySpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentRemovedChange>(),
- componentSpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentRemovedChange>() }) {
+ {
+ const auto event = entitySpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentRemovedChange>();
QCOMPARE(event->type(), Qt3DCore::ComponentRemoved);
QCOMPARE(event->subjectId(), entity->id());
QCOMPARE(event->entityId(), entity->id());
QCOMPARE(event->componentId(), comp->id());
QCOMPARE(event->componentMetaObject(), comp->metaObject());
}
+ {
+ const auto event = componentSpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentRemovedChange>();
+ QCOMPARE(event->type(), Qt3DCore::ComponentRemoved);
+ QCOMPARE(event->subjectId(), comp->id());
+ QCOMPARE(event->entityId(), entity->id());
+ QCOMPARE(event->componentId(), comp->id());
+ QCOMPARE(event->componentMetaObject(), comp->metaObject());
+ }
}
}
diff --git a/tests/auto/render/boundingsphere/tst_boundingsphere.cpp b/tests/auto/render/boundingsphere/tst_boundingsphere.cpp
index fcbfaf6ba..620c74641 100644
--- a/tests/auto/render/boundingsphere/tst_boundingsphere.cpp
+++ b/tests/auto/render/boundingsphere/tst_boundingsphere.cpp
@@ -65,6 +65,8 @@
#include <Qt3DExtras/qcuboidmesh.h>
#include <Qt3DExtras/qplanemesh.h>
+#include <qbackendnodetester.h>
+
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
@@ -100,6 +102,7 @@ public:
Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const { return d_func()->m_renderer->frameGraphRoot(); }
Qt3DRender::Render::RenderSettings *renderSettings() const { return d_func()->m_renderer->settings(); }
Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; }
+ Qt3DRender::Render::AbstractRenderer *renderer() const { return d_func()->m_renderer; }
private:
Render::Entity *m_sceneRoot;
@@ -153,7 +156,7 @@ void runRequiredJobs(Qt3DRender::TestAspect *test)
} // anonymous
-class tst_BoundingSphere : public QObject
+class tst_BoundingSphere : public Qt3DCore::QBackendNodeTester
{
Q_OBJECT
private:
@@ -194,6 +197,229 @@ private Q_SLOTS:
QVERIFY(qAbs(boundingSphere->center().y() - sphereCenter.y()) < 0.000001f);
QVERIFY(qAbs(boundingSphere->center().z() - sphereCenter.z()) < 0.000001f);
}
+
+ void checkCustomGeometry_data()
+ {
+ QTest::addColumn<int>("drawVertexCount");
+ QTest::addColumn<int>("indexByteOffset");
+ QTest::addColumn<QVector3D>("expectedCenter");
+ QTest::addColumn<float>("expectedRadius");
+ QTest::newRow("all") << 0 << 0 << QVector3D(-0.488892f, 0.0192147f, -75.4804f) << 25.5442f;
+ QTest::newRow("first only") << 3 << 0 << QVector3D(0, 1, -100) << 1.0f;
+ QTest::newRow("second only") << 3 << int(3 * sizeof(ushort)) << QVector3D(0, -1, -50) << 1.0f;
+ }
+
+ void checkCustomGeometry()
+ {
+ QFETCH(int, drawVertexCount);
+ QFETCH(int, indexByteOffset);
+ QFETCH(QVector3D, expectedCenter);
+ QFETCH(float, expectedRadius);
+
+ // two triangles with different Z, and an index buffer
+ QByteArray vdata;
+ vdata.resize(6 * 3 * sizeof(float));
+ float *vp = reinterpret_cast<float *>(vdata.data());
+ *vp++ = -1.0f;
+ *vp++ = 1.0f;
+ *vp++ = -100.0f;
+ *vp++ = 0.0f;
+ *vp++ = 0.0f;
+ *vp++ = -100.0f;
+ *vp++ = 1.0f;
+ *vp++ = 1.0f;
+ *vp++ = -100.0f;
+
+ *vp++ = -1.0f;
+ *vp++ = -1.0f;
+ *vp++ = -50.0f;
+ *vp++ = 0.0f;
+ *vp++ = 0.0f;
+ *vp++ = -50.0f;
+ *vp++ = 1.0f;
+ *vp++ = -1.0f;
+ *vp++ = -50.0f;
+
+ QByteArray idata;
+ idata.resize(6 * sizeof(ushort));
+ ushort *ip = reinterpret_cast<ushort *>(idata.data());
+ *ip++ = 0;
+ *ip++ = 1;
+ *ip++ = 2;
+ *ip++ = 3;
+ *ip++ = 4;
+ *ip++ = 5;
+
+ QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity);
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(entity.data()));
+ Qt3DRender::QBuffer *vbuffer = new Qt3DRender::QBuffer;
+ Qt3DRender::QBuffer *ibuffer = new Qt3DRender::QBuffer;
+
+ vbuffer->setData(vdata);
+ Qt3DRender::Render::Buffer *vbufferBackend = test->nodeManagers()->bufferManager()->getOrCreateResource(vbuffer->id());
+ vbufferBackend->setRenderer(test->renderer());
+ vbufferBackend->setManager(test->nodeManagers()->bufferManager());
+ simulateInitialization(vbuffer, vbufferBackend);
+
+ ibuffer->setData(idata);
+ Qt3DRender::Render::Buffer *ibufferBackend = test->nodeManagers()->bufferManager()->getOrCreateResource(ibuffer->id());
+ ibufferBackend->setRenderer(test->renderer());
+ ibufferBackend->setManager(test->nodeManagers()->bufferManager());
+ simulateInitialization(ibuffer, ibufferBackend);
+
+ Qt3DRender::QGeometry *g = new Qt3DRender::QGeometry;
+ for (int i = 0; i < 2; ++i)
+ g->addAttribute(new Qt3DRender::QAttribute);
+
+ const QVector<Qt3DRender::QAttribute *> attrs = g->attributes();
+ Qt3DRender::QAttribute *attr = attrs[0];
+ attr->setBuffer(vbuffer);
+ attr->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
+ attr->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ attr->setVertexSize(3);
+ attr->setCount(6);
+ attr->setByteOffset(0);
+ attr->setByteStride(3 * sizeof(float));
+
+ attr = attrs[1];
+ attr->setBuffer(ibuffer);
+ attr->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
+ attr->setVertexBaseType(Qt3DRender::QAttribute::UnsignedShort);
+ attr->setVertexSize(1);
+ attr->setCount(6);
+ attr->setByteOffset(indexByteOffset);
+
+ Qt3DRender::QGeometryRenderer *gr = new Qt3DRender::QGeometryRenderer;
+ gr->setVertexCount(drawVertexCount); // when 0, indexAttribute->count() is used instead
+ gr->setGeometry(g);
+ entity->addComponent(gr);
+
+ Qt3DRender::Render::Attribute *attr0Backend = test->nodeManagers()->attributeManager()->getOrCreateResource(attrs[0]->id());
+ attr0Backend->setRenderer(test->renderer());
+ simulateInitialization(attrs[0], attr0Backend);
+ Qt3DRender::Render::Attribute *attr1Backend = test->nodeManagers()->attributeManager()->getOrCreateResource(attrs[1]->id());
+ attr1Backend->setRenderer(test->renderer());
+ simulateInitialization(attrs[1], attr1Backend);
+
+ Qt3DRender::Render::Geometry *gBackend = test->nodeManagers()->geometryManager()->getOrCreateResource(g->id());
+ gBackend->setRenderer(test->renderer());
+ simulateInitialization(g, gBackend);
+
+ Qt3DRender::Render::GeometryRenderer *grBackend = test->nodeManagers()->geometryRendererManager()->getOrCreateResource(gr->id());
+ grBackend->setRenderer(test->renderer());
+ grBackend->setManager(test->nodeManagers()->geometryRendererManager());
+ simulateInitialization(gr, grBackend);
+
+ Qt3DRender::Render::Entity *entityBackend = test->nodeManagers()->renderNodesManager()->getOrCreateResource(entity->id());
+ entityBackend->setRenderer(test->renderer());
+ simulateInitialization(entity.data(), entityBackend);
+
+ Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
+ calcBVolume.setManagers(test->nodeManagers());
+ calcBVolume.setRoot(test->sceneRoot());
+ calcBVolume.run();
+
+ Vector3D center = entityBackend->localBoundingVolume()->center();
+ float radius = entityBackend->localBoundingVolume()->radius();
+ qDebug() << radius << center;
+
+ // truncate and compare integers only
+ QVERIFY(int(radius) == int(expectedRadius));
+ QVERIFY(int(center.x()) == int(expectedCenter.x()));
+ QVERIFY(int(center.y()) == int(expectedCenter.y()));
+ QVERIFY(int(center.z()) == int(expectedCenter.z()));
+ }
+
+ void checkCustomPackedGeometry()
+ {
+ int drawVertexCount = 6;
+ QVector3D expectedCenter(-0.488892f, 0.0192147f, -75.4804f);
+ float expectedRadius = 25.5442f;
+
+ // two triangles with different Z
+ QByteArray vdata;
+ vdata.resize(6 * 3 * sizeof(float));
+ float *vp = reinterpret_cast<float *>(vdata.data());
+ *vp++ = -1.0f;
+ *vp++ = 1.0f;
+ *vp++ = -100.0f;
+ *vp++ = 0.0f;
+ *vp++ = 0.0f;
+ *vp++ = -100.0f;
+ *vp++ = 1.0f;
+ *vp++ = 1.0f;
+ *vp++ = -100.0f;
+
+ *vp++ = -1.0f;
+ *vp++ = -1.0f;
+ *vp++ = -50.0f;
+ *vp++ = 0.0f;
+ *vp++ = 0.0f;
+ *vp++ = -50.0f;
+ *vp++ = 1.0f;
+ *vp++ = -1.0f;
+ *vp++ = -50.0f;
+
+ QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity);
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(entity.data()));
+ Qt3DRender::QBuffer *vbuffer = new Qt3DRender::QBuffer;
+
+ vbuffer->setData(vdata);
+ Qt3DRender::Render::Buffer *vbufferBackend = test->nodeManagers()->bufferManager()->getOrCreateResource(vbuffer->id());
+ vbufferBackend->setRenderer(test->renderer());
+ vbufferBackend->setManager(test->nodeManagers()->bufferManager());
+ simulateInitialization(vbuffer, vbufferBackend);
+
+ Qt3DRender::QGeometry *g = new Qt3DRender::QGeometry;
+ g->addAttribute(new Qt3DRender::QAttribute);
+
+ const QVector<Qt3DRender::QAttribute *> attrs = g->attributes();
+ Qt3DRender::QAttribute *attr = attrs[0];
+ attr->setBuffer(vbuffer);
+ attr->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
+ attr->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ attr->setVertexSize(3);
+ attr->setCount(6);
+ attr->setByteOffset(0);
+ attr->setByteStride(0);
+
+ Qt3DRender::QGeometryRenderer *gr = new Qt3DRender::QGeometryRenderer;
+ gr->setVertexCount(drawVertexCount);
+ gr->setGeometry(g);
+ entity->addComponent(gr);
+
+ Qt3DRender::Render::Attribute *attr0Backend = test->nodeManagers()->attributeManager()->getOrCreateResource(attrs[0]->id());
+ attr0Backend->setRenderer(test->renderer());
+ simulateInitialization(attrs[0], attr0Backend);
+
+ Qt3DRender::Render::Geometry *gBackend = test->nodeManagers()->geometryManager()->getOrCreateResource(g->id());
+ gBackend->setRenderer(test->renderer());
+ simulateInitialization(g, gBackend);
+
+ Qt3DRender::Render::GeometryRenderer *grBackend = test->nodeManagers()->geometryRendererManager()->getOrCreateResource(gr->id());
+ grBackend->setRenderer(test->renderer());
+ grBackend->setManager(test->nodeManagers()->geometryRendererManager());
+ simulateInitialization(gr, grBackend);
+
+ Qt3DRender::Render::Entity *entityBackend = test->nodeManagers()->renderNodesManager()->getOrCreateResource(entity->id());
+ entityBackend->setRenderer(test->renderer());
+ simulateInitialization(entity.data(), entityBackend);
+
+ Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
+ calcBVolume.setManagers(test->nodeManagers());
+ calcBVolume.setRoot(test->sceneRoot());
+ calcBVolume.run();
+
+ Vector3D center = entityBackend->localBoundingVolume()->center();
+ float radius = entityBackend->localBoundingVolume()->radius();
+ qDebug() << radius << center;
+
+ // truncate and compare integers only
+ QVERIFY(int(radius) == int(expectedRadius));
+ QVERIFY(int(center.x()) == int(expectedCenter.x()));
+ QVERIFY(int(center.y()) == int(expectedCenter.y()));
+ QVERIFY(int(center.z()) == int(expectedCenter.z()));
+ }
};
QTEST_MAIN(tst_BoundingSphere)
diff --git a/tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.qrc b/tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.qrc
index c2b0c7fff..feef480e2 100644
--- a/tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.qrc
+++ b/tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.qrc
@@ -8,5 +8,7 @@
<file>testscene_pickersdisabled.qml</file>
<file>testscene_dragenabledoverlapping.qml</file>
<file>testscene_parententity.qml</file>
+ <file>testscene_viewports.qml</file>
+ <file>testscene_cameraposition.qml</file>
</qresource>
</RCC>
diff --git a/tests/auto/render/pickboundingvolumejob/testscene_cameraposition.qml b/tests/auto/render/pickboundingvolumejob/testscene_cameraposition.qml
new file mode 100644
index 000000000..87e7a8aac
--- /dev/null
+++ b/tests/auto/render/pickboundingvolumejob/testscene_cameraposition.qml
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+import QtQuick.Window 2.0
+
+Entity {
+ id: sceneRoot
+
+ Window {
+ id: win
+ width: 600
+ height: 600
+ visible: true
+ }
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 5.0, 3.0, 1.0 )
+ }
+
+ components: [
+ RenderSettings {
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
+
+ RenderSurfaceSelector {
+
+ surface: win
+
+ ClearBuffers {
+ buffers : ClearBuffers.ColorDepthBuffer
+ NoDraw {}
+ }
+
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+ }
+ ]
+
+ CuboidMesh { id: cubeMesh }
+ PhongMaterial { id: material }
+
+ Entity {
+ property ObjectPicker picker: ObjectPicker {
+ objectName: "Picker"
+ }
+
+ property Transform transform: Transform {
+ translation: camera.viewCenter
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, picker, transform]
+ }
+
+}
diff --git a/tests/auto/render/pickboundingvolumejob/testscene_viewports.qml b/tests/auto/render/pickboundingvolumejob/testscene_viewports.qml
new file mode 100644
index 000000000..daafc0edd
--- /dev/null
+++ b/tests/auto/render/pickboundingvolumejob/testscene_viewports.qml
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+import QtQuick.Window 2.0
+
+Entity {
+ id: sceneRoot
+
+ Window {
+ id: _view
+ width: 600
+ height: 600
+ visible: true
+ }
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: _view.width / 2 / _view.height
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -10.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ Camera {
+ id: camera2
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: _view.width / _view.height
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -20.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ FirstPersonCameraController {
+ camera: camera
+ }
+
+ DirectionalLight {
+ worldDirection: camera.viewVector.times(-1)
+ }
+
+ // Draw 2 viewports
+ // one with the content, the other with content + debug volumes
+ components: [
+ RenderSettings {
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
+
+ RenderSurfaceSelector {
+ surface: _view
+
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 0.5, 1.0)
+ ClearBuffers {
+ buffers : ClearBuffers.ColorDepthBuffer
+ clearColor: "white"
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+
+ Viewport {
+ normalizedRect: Qt.rect(0.5, 0.0, 0.5, 1.0)
+ CameraSelector {
+ camera: camera2
+ }
+ }
+ }
+ }
+ }
+ ]
+
+ CuboidMesh { id: cubeMesh }
+
+ Entity {
+ readonly property ObjectPicker objectPicker: ObjectPicker {
+ onClicked: console.log("o1")
+ }
+ readonly property Transform transform: Transform {
+ scale: 3
+ translation: Qt.vector3d(3, 0, 0)
+ }
+ readonly property PhongMaterial material: PhongMaterial { diffuse: "red" }
+
+ components: [cubeMesh, transform, material, objectPicker ]
+ }
+
+ Entity {
+ readonly property ObjectPicker objectPicker: ObjectPicker {
+ objectName: "Picker2"
+ onClicked: console.log("o2")
+ }
+ readonly property Transform transform: Transform {
+ scale: 3
+ translation: Qt.vector3d(-3, 0, 0)
+ }
+ readonly property PhongMaterial material: PhongMaterial { diffuse: "green" }
+
+ components: [cubeMesh, transform, material, objectPicker ]
+ }
+}
diff --git a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
index a14bccefc..b86df05a4 100644
--- a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
+++ b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
@@ -234,7 +234,7 @@ private Q_SLOTS:
// WHEN
Qt3DRender::Render::PickingUtils::ViewportCameraAreaGatherer gatherer;
- QVector<Qt3DRender::Render::PickingUtils::ViewportCameraAreaTriplet> results = gatherer.gather(test->frameGraphRoot());
+ QVector<Qt3DRender::Render::PickingUtils::ViewportCameraAreaDetails> results = gatherer.gather(test->frameGraphRoot());
// THEN
QCOMPARE(results.size(), 1);
@@ -329,8 +329,8 @@ private Q_SLOTS:
QVERIFY(pickBVJob.currentPicker().isNull());
// WHEN
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *,QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
bool earlyReturn = !pickBVJob.runHelper();
@@ -343,7 +343,7 @@ private Q_SLOTS:
// WHEN
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -353,7 +353,7 @@ private Q_SLOTS:
// WHEN
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(390.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(390.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -366,7 +366,7 @@ private Q_SLOTS:
// WHEN
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(390.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(390.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -425,8 +425,9 @@ private Q_SLOTS:
QVERIFY(earlyReturn);
// WHEN
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 440.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 440.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -474,8 +475,9 @@ private Q_SLOTS:
Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
initializePickBoundingVolumeJob(&pickBVJob, test.data());
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
// THEN
@@ -530,9 +532,9 @@ private Q_SLOTS:
Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
initializePickBoundingVolumeJob(&pickBVJob, test.data());
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f),
- Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
bool earlyReturn = !pickBVJob.runHelper();
@@ -580,8 +582,9 @@ private Q_SLOTS:
Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
initializePickBoundingVolumeJob(&pickBVJob, test.data());
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
bool earlyReturn = !pickBVJob.runHelper();
@@ -591,7 +594,8 @@ private Q_SLOTS:
// WHEN
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -639,8 +643,9 @@ private Q_SLOTS:
Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
initializePickBoundingVolumeJob(&pickBVJob, test.data());
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
bool earlyReturn = !pickBVJob.runHelper();
@@ -650,7 +655,8 @@ private Q_SLOTS:
// WHEN
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -698,8 +704,9 @@ private Q_SLOTS:
Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
initializePickBoundingVolumeJob(&pickBVJob, test.data());
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
const bool earlyReturn = !pickBVJob.runHelper();
@@ -764,8 +771,9 @@ private Q_SLOTS:
Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
initializePickBoundingVolumeJob(&pickBVJob, test.data());
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
bool earlyReturn = !pickBVJob.runHelper();
@@ -785,7 +793,8 @@ private Q_SLOTS:
// WHEN -> Move on same object
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -805,7 +814,8 @@ private Q_SLOTS:
// WHEN -> Release on object
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -832,8 +842,10 @@ private Q_SLOTS:
// WHEN -> Release outside of object
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(0.0f, 0.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -900,8 +912,9 @@ private Q_SLOTS:
Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
initializePickBoundingVolumeJob(&pickBVJob, test.data());
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::HoverMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::HoverMove, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
bool earlyReturn = !pickBVJob.runHelper();
@@ -916,7 +929,8 @@ private Q_SLOTS:
// WHEN -> HoverMove Out
events.clear();
- events.push_back(QMouseEvent(QEvent::HoverMove, QPointF(20.0f, 40.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QEvent::HoverMove, QPointF(20.0f, 40.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -931,8 +945,10 @@ private Q_SLOTS:
// WHEN -> HoverMove In + Pressed other
events.clear();
- events.push_back(QMouseEvent(QEvent::HoverMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
- events.push_back(QMouseEvent(QEvent::MouseButtonPress, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QEvent::HoverMove, QPointF(207.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
+ events.push_back({nullptr, QMouseEvent(QEvent::MouseButtonPress, QPointF(0.0f, 0.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -1001,8 +1017,9 @@ private Q_SLOTS:
Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
initializePickBoundingVolumeJob(&pickBVJob, test.data());
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 300.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
bool earlyReturn = !pickBVJob.runHelper();
@@ -1017,7 +1034,8 @@ private Q_SLOTS:
// WHEN -> Move on same object
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(400.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(400.0f, 300.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -1032,7 +1050,8 @@ private Q_SLOTS:
// WHEN -> Release on object
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(400.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(400.0f, 300.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -1049,8 +1068,10 @@ private Q_SLOTS:
// WHEN -> Release outside of object
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 300.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(0.0f, 0.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -1126,8 +1147,9 @@ private Q_SLOTS:
Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
initializePickBoundingVolumeJob(&pickBVJob, test.data());
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(320.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(320.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
bool earlyReturn = !pickBVJob.runHelper();
@@ -1141,7 +1163,8 @@ private Q_SLOTS:
// WHEN -> Move on next object, show stay on previous picker unless all picks are requested
events.clear();
- events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(280.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(280.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
earlyReturn = !pickBVJob.runHelper();
@@ -1200,8 +1223,9 @@ private Q_SLOTS:
Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
initializePickBoundingVolumeJob(&pickBVJob, test.data());
- QList<QMouseEvent> events;
- events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 300.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
pickBVJob.setMouseEvents(events);
bool earlyReturn = !pickBVJob.runHelper();
@@ -1212,6 +1236,155 @@ private Q_SLOTS:
Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
QCOMPARE(change->propertyName(), "pressed");
}
+
+ void checkPickerAndViewports()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_viewports.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ settings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
+ settings->setPickResultMode(Qt3DRender::QPickingSettings::NearestPick);
+ settings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontFace);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+ TestArbiter arbiter;
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ // object partially obscured by another viewport, make sure only visible portion is pickable
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 2);
+
+ Qt3DRender::QObjectPicker *picker = pickers.last();
+ QCOMPARE(picker->objectName(), QLatin1String("Picker2"));
+
+ Qt3DRender::Render::ObjectPicker *backendPicker = test->nodeManagers()->objectPickerManager()->lookupResource(picker->id());
+ QVERIFY(backendPicker);
+ Qt3DCore::QBackendNodePrivate::get(backendPicker)->setArbiter(&arbiter);
+
+ // WHEN -> Pressed on object in vp1
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(280.0f, 300.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
+ pickBVJob.setMouseEvents(events);
+ bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Pressed
+ QVERIFY(!earlyReturn);
+ QVERIFY(backendPicker->isPressed());
+ QCOMPARE(arbiter.events.count(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "pressed");
+
+ // WHEN reset -> Presset on object in vp2
+ backendPicker->cleanup();
+ backendPicker->setEnabled(true);
+ events.clear();
+ arbiter.events.clear();
+
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(320.0f, 300.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Nothing happened
+ QVERIFY(!earlyReturn);
+ QVERIFY(!backendPicker->isPressed());
+ QCOMPARE(arbiter.events.count(), 0);
+ }
+
+ void checkMultipleRayDirections_data()
+ {
+ QTest::addColumn<QVector3D>("cameraOrigin");
+ QTest::addColumn<QVector3D>("cameraUpVector");
+
+ int k = 0;
+ const int n = 10;
+ for (int j=0; j<n; j++) {
+ QMatrix4x4 m;
+ m.rotate(360.f / (float)n * (float)j, 0.f, 0.f, 1.f);
+ for (int i=0; i<n; i++) {
+ const double angle = M_PI * 2. / (double)n * i;
+ const double x = std::sin(angle) * 10.;
+ const double z = std::cos(angle) * 10.;
+ QVector3D pos(x, 0, z);
+ QVector3D up(0, 1, 0);
+ QTest::newRow(QString::number(k++).toLatin1().data()) << m * pos << m * up;
+ }
+ }
+ }
+
+ void checkMultipleRayDirections()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_cameraposition.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ settings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+ TestArbiter arbiter;
+
+ QList<Qt3DRender::QCamera *> cameras = root->findChildren<Qt3DRender::QCamera *>();
+ QCOMPARE(cameras.size(), 1);
+ Qt3DRender::QCamera *camera = cameras.first();
+
+ QFETCH(QVector3D, cameraUpVector);
+ camera->setUpVector(cameraUpVector);
+
+ QFETCH(QVector3D, cameraOrigin);
+ camera->setPosition(cameraOrigin);
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 1);
+
+ Qt3DRender::QObjectPicker *picker = pickers.front();
+
+ Qt3DRender::Render::ObjectPicker *backendPicker = test->nodeManagers()->objectPickerManager()->lookupResource(picker->id());
+ QVERIFY(backendPicker);
+ Qt3DCore::QBackendNodePrivate::get(backendPicker)->setArbiter(&arbiter);
+
+ // WHEN -> Pressed on object
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ QList<QPair<QObject *, QMouseEvent>> events;
+ events.push_back({nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(303.0f, 303.0f),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
+ pickBVJob.setMouseEvents(events);
+ bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Pressed
+ QVERIFY(!earlyReturn);
+ QVERIFY(backendPicker->isPressed());
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "pressed");
+ Qt3DRender::QPickEventPtr pickEvent = change->value().value<Qt3DRender::QPickEventPtr>();
+ QVERIFY(pickEvent);
+
+ arbiter.events.clear();
+ }
+
};
QTEST_MAIN(tst_PickBoundingVolumeJob)
diff --git a/tests/auto/render/shadercache/tst_shadercache.cpp b/tests/auto/render/shadercache/tst_shadercache.cpp
index 1c70d4405..49628ef0f 100644
--- a/tests/auto/render/shadercache/tst_shadercache.cpp
+++ b/tests/auto/render/shadercache/tst_shadercache.cpp
@@ -131,6 +131,19 @@ void tst_ShaderCache::value()
auto dnaC = ProgramDNA(54321);
auto uncachedProgram = cache.getShaderProgramAndAddRef(dnaC, nodeIdB);
QVERIFY(uncachedProgram == nullptr);
+
+ cache.clear();
+ // Test inserting nullptr.
+ cache.insert(dnaA, nodeIdA, nullptr);
+ bool wasPresent = false;
+ cachedProgramA = cache.getShaderProgramAndAddRef(dnaA, nodeIdA, &wasPresent);
+ QCOMPARE(wasPresent, true);
+ QCOMPARE(cachedProgramA, nullptr);
+ cache.clear();
+ // Test wasPresent==false.
+ cachedProgramB = cache.getShaderProgramAndAddRef(dnaB, nodeIdB, &wasPresent);
+ QCOMPARE(wasPresent, false);
+ QCOMPARE(cachedProgramB, nullptr);
}
void tst_ShaderCache::removeRef()
diff --git a/tests/auto/render/trianglevisitor/tst_trianglevisitor.cpp b/tests/auto/render/trianglevisitor/tst_trianglevisitor.cpp
index 6a9be5e13..4205d598e 100644
--- a/tests/auto/render/trianglevisitor/tst_trianglevisitor.cpp
+++ b/tests/auto/render/trianglevisitor/tst_trianglevisitor.cpp
@@ -194,7 +194,7 @@ private Q_SLOTS:
positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
- positionAttribute->setByteStride(3*4);
+ positionAttribute->setByteStride(0);
positionAttribute->setByteOffset(0);
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
geometry->addAttribute(positionAttribute.data());