summaryrefslogtreecommitdiffstats
path: root/src
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 /src
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
Diffstat (limited to 'src')
-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
34 files changed, 417 insertions, 201 deletions
diff --git a/src/core/changes/qcomponentaddedchange.cpp b/src/core/changes/qcomponentaddedchange.cpp
index e00c4ffab..41f7a2340 100644
--- a/src/core/changes/qcomponentaddedchange.cpp
+++ b/src/core/changes/qcomponentaddedchange.cpp
@@ -75,7 +75,7 @@ QComponentAddedChangePrivate::QComponentAddedChangePrivate(const QEntity *entity
*/
/*!
- * Constructs a new QComponentAddedChange with with \a entity and \a component.
+ * Constructs a new QComponentAddedChange which will notify \a entity that \a component was added
*/
QComponentAddedChange::QComponentAddedChange(const QEntity *entity,
const QComponent *component)
@@ -84,6 +84,16 @@ QComponentAddedChange::QComponentAddedChange(const QEntity *entity,
{
}
+/*!
+ * Constructs a new QComponentAddedChange which will notify \a component that it was added to \a entity
+ */
+QComponentAddedChange::QComponentAddedChange(const QComponent *component,
+ const QEntity *entity)
+ : QSceneChange(*new QComponentAddedChangePrivate(entity, component),
+ ComponentAdded, component->id())
+{
+}
+
QComponentAddedChange::~QComponentAddedChange()
{
}
diff --git a/src/core/changes/qcomponentaddedchange.h b/src/core/changes/qcomponentaddedchange.h
index a62cac116..e7676a026 100644
--- a/src/core/changes/qcomponentaddedchange.h
+++ b/src/core/changes/qcomponentaddedchange.h
@@ -55,6 +55,8 @@ class QT3DCORESHARED_EXPORT QComponentAddedChange : public QSceneChange
public:
explicit QComponentAddedChange(const QEntity *entity,
const QComponent *component);
+ explicit QComponentAddedChange(const QComponent *component,
+ const QEntity *entity);
~QComponentAddedChange();
QNodeId entityId() const Q_DECL_NOTHROW;
diff --git a/src/core/changes/qcomponentremovedchange.cpp b/src/core/changes/qcomponentremovedchange.cpp
index 5e5dfa5aa..e2129169a 100644
--- a/src/core/changes/qcomponentremovedchange.cpp
+++ b/src/core/changes/qcomponentremovedchange.cpp
@@ -75,7 +75,7 @@ QComponentRemovedChangePrivate::QComponentRemovedChangePrivate(const QEntity *en
*/
/*!
- * Constructs a new QComponentRemovedChange with \a entity and \a component.
+ * Constructs a new QComponentRemovedChange which will notify \a entity that \a component was removed.
*/
QComponentRemovedChange::QComponentRemovedChange(const QEntity *entity,
const QComponent *component)
@@ -84,6 +84,17 @@ QComponentRemovedChange::QComponentRemovedChange(const QEntity *entity,
{
}
+/*!
+ * Constructs a new QComponentRemovedChange which will notify \a component that it was removed from \a entity
+ */
+QComponentRemovedChange::QComponentRemovedChange(const QComponent *component,
+ const QEntity *entity)
+ : QSceneChange(*new QComponentRemovedChangePrivate(entity, component),
+ ComponentRemoved, component->id())
+{
+
+}
+
QComponentRemovedChange::~QComponentRemovedChange()
{
}
diff --git a/src/core/changes/qcomponentremovedchange.h b/src/core/changes/qcomponentremovedchange.h
index 3c57fe26f..66743b1ae 100644
--- a/src/core/changes/qcomponentremovedchange.h
+++ b/src/core/changes/qcomponentremovedchange.h
@@ -55,6 +55,8 @@ class QT3DCORESHARED_EXPORT QComponentRemovedChange : public QSceneChange
public:
explicit QComponentRemovedChange(const QEntity *entity,
const QComponent *component);
+ explicit QComponentRemovedChange(const QComponent *component,
+ const QEntity *entity);
~QComponentRemovedChange();
QNodeId entityId() const Q_DECL_NOTHROW;
diff --git a/src/core/changes/qpropertynodeaddedchange.cpp b/src/core/changes/qpropertynodeaddedchange.cpp
index 390a170b6..9f8e50872 100644
--- a/src/core/changes/qpropertynodeaddedchange.cpp
+++ b/src/core/changes/qpropertynodeaddedchange.cpp
@@ -76,6 +76,16 @@ QPropertyNodeAddedChange::QPropertyNodeAddedChange(QNodeId subjectId, QNode *nod
{
Q_D(QPropertyNodeAddedChange);
d->m_addedNodeIdTypePair = QNodeIdTypePair(node->id(), QNodePrivate::findStaticMetaObject(node->metaObject()));
+
+ // Ensure the node has issued a node creation change. We can end
+ // up here if a newly created node with a parent is immediately set
+ // as a property on another node. In this case the deferred call to
+ // _q_postConstructorInit() will not have happened yet as the event
+ // loop will still be blocked. So force it here and we catch this
+ // eventuality in the _q_postConstructorInit() function so that we
+ // do not repeat the creation and new child scene change events.
+ if (node)
+ QNodePrivate::get(node)->_q_postConstructorInit();
}
/*! \internal */
diff --git a/src/core/nodes/qcomponent.cpp b/src/core/nodes/qcomponent.cpp
index 8e337adf6..f4e59e058 100644
--- a/src/core/nodes/qcomponent.cpp
+++ b/src/core/nodes/qcomponent.cpp
@@ -73,7 +73,7 @@ void QComponentPrivate::addEntity(QEntity *entity)
m_scene->addEntityForComponent(m_id, entity->id());
}
- const auto componentAddedChange = QComponentAddedChangePtr::create(entity, q);
+ const auto componentAddedChange = QComponentAddedChangePtr::create(q, entity);
notifyObservers(componentAddedChange);
Q_EMIT q->addedToEntity(entity);
}
@@ -86,7 +86,7 @@ void QComponentPrivate::removeEntity(QEntity *entity)
m_entities.removeAll(entity);
- const auto componentRemovedChange = QComponentRemovedChangePtr::create(entity, q);
+ const auto componentRemovedChange = QComponentRemovedChangePtr::create(q, entity);
notifyObservers(componentRemovedChange);
Q_EMIT q->removedFromEntity(entity);
}
diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp
index dbe3fd102..083fda7df 100644
--- a/src/core/nodes/qnode.cpp
+++ b/src/core/nodes/qnode.cpp
@@ -74,6 +74,7 @@ QNodePrivate::QNodePrivate()
, m_blockNotifications(false)
, m_hasBackendNode(false)
, m_enabled(true)
+ , m_notifiedParent(false)
, m_defaultPropertyTrackMode(QNode::TrackFinalValues)
, m_propertyChangesSetup(false)
, m_signals(this)
@@ -210,13 +211,19 @@ void QNodePrivate::_q_addChild(QNode *childNode)
Q_ASSERT(childNode);
Q_ASSERT_X(childNode->parent() == q_func(), Q_FUNC_INFO, "not a child of this node");
+ // Have we already notified the parent about its new child? If so, bail out
+ // early so that we do not send more than one new child event to the backend
+ QNodePrivate *childD = QNodePrivate::get(childNode);
+ if (childD->m_notifiedParent == true)
+ return;
+
// Store our id as the parentId in the child so that even if the child gets
// removed from the scene as part of the destruction of the parent, when the
// parent's children are deleted in the QObject dtor, we still have access to
// the parentId. If we didn't store this, we wouldn't have access at that time
// because the parent would then only be a QObject, the QNode part would have
// been destroyed already.
- QNodePrivate::get(childNode)->m_parentId = m_id;
+ childD->m_parentId = m_id;
if (!m_scene)
return;
@@ -224,6 +231,11 @@ void QNodePrivate::_q_addChild(QNode *childNode)
// We need to send a QPropertyNodeAddedChange to the backend
// to notify the backend that we have a new child
if (m_changeArbiter != nullptr) {
+ // Flag that we have notified the parent. We do this immediately before
+ // creating the change because that recurses back into this function and
+ // we need to catch that to avoid sending more than one new child event
+ // to the backend.
+ childD->m_notifiedParent = true;
const auto change = QPropertyNodeAddedChangePtr::create(m_id, childNode);
change->setPropertyName("children");
notifyObservers(change);
@@ -299,6 +311,9 @@ void QNodePrivate::_q_setParentHelper(QNode *parent)
notifyDestructionChangesAndRemoveFromScene();
}
+ // Flag that we need to notify any new parent
+ m_notifiedParent = false;
+
// Basically QObject::setParent but for QObjectPrivate
QObjectPrivate::setParent_helper(parent);
QNode *newParentNode = q->parentNode();
@@ -373,28 +388,43 @@ void QNodePrivate::propertyChanged(int propertyIndex)
if (m_blockNotifications)
return;
+ const auto toBackendValue = [this](const QVariant &data) -> QVariant
+ {
+ if (data.canConvert<QNode*>()) {
+ QNode *node = data.value<QNode*>();
+
+ // Ensure the node has issued a node creation change. We can end
+ // up here if a newly created node with a parent is immediately set
+ // as a property on another node. In this case the deferred call to
+ // _q_postConstructorInit() will not have happened yet as the event
+ // loop will still be blocked. So force it here and we catch this
+ // eventuality in the _q_postConstructorInit() function so that we
+ // do not repeat the creation and new child scene change events.
+ if (node)
+ QNodePrivate::get(node)->_q_postConstructorInit();
+
+ const QNodeId id = node ? node->id() : QNodeId();
+ return QVariant::fromValue(id);
+ }
+
+ return data;
+ };
+
Q_Q(QNode);
const QMetaProperty property = q->metaObject()->property(propertyIndex);
const QVariant data = property.read(q);
- if (data.canConvert<QNode*>()) {
- QNode *node = data.value<QNode*>();
-
- // Ensure the node has issued a node creation change. We can end
- // up here if a newly created node with a parent is immediately set
- // as a property on another node. In this case the deferred call to
- // _q_postConstructorInit() will not have happened yet as the event
- // loop will still be blocked. So force it here and we catch this
- // eventuality in the _q_postConstructorInit() function so that we
- // do not repeat the creation and new child scene change events.
- if (node)
- QNodePrivate::get(node)->_q_postConstructorInit();
-
- const QNodeId id = node ? node->id() : QNodeId();
- notifyPropertyChange(property.name(), QVariant::fromValue(id));
+
+ if (data.type() == QVariant::List) {
+ QSequentialIterable iterable = data.value<QSequentialIterable>();
+ QVariantList variants;
+ variants.reserve(iterable.size());
+ for (const auto &v : iterable)
+ variants.append(toBackendValue(v));
+ notifyPropertyChange(property.name(), variants);
} else {
- notifyPropertyChange(property.name(), data);
+ notifyPropertyChange(property.name(), toBackendValue(data));
}
}
diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h
index ad9d2376e..87a0226f1 100644
--- a/src/core/nodes/qnode_p.h
+++ b/src/core/nodes/qnode_p.h
@@ -100,6 +100,7 @@ public:
bool m_blockNotifications;
bool m_hasBackendNode;
bool m_enabled;
+ bool m_notifiedParent;
QNode::PropertyTrackingMode m_defaultPropertyTrackMode;
QHash<QString, QNode::PropertyTrackingMode> m_trackedPropertiesOverrides;
@@ -137,10 +138,11 @@ public:
static const QMetaObject *findStaticMetaObject(const QMetaObject *metaObject);
+ void _q_postConstructorInit();
+
private:
void notifyCreationChange();
void notifyDestructionChangesAndRemoveFromScene();
- void _q_postConstructorInit();
void _q_addChild(QNode *childNode);
void _q_removeChild(QNode *childNode);
void _q_setParentHelper(QNode *parent);
diff --git a/src/doc/src/qt3danimation-module.qdoc b/src/doc/src/qt3danimation-module.qdoc
index ed3406aa4..a926df67d 100644
--- a/src/doc/src/qt3danimation-module.qdoc
+++ b/src/doc/src/qt3danimation-module.qdoc
@@ -30,7 +30,7 @@
\module Qt3DAnimation
\title Qt 3D Animation C++ Classes
- \brief The Qt 3D Animation modules provides a set of prebuilt elements to help
+ \brief The Qt 3D Animation module provides a set of prebuilt elements to help
you get started with Qt 3D.
This module is still in tech preview. This means it is unstable, likely to
diff --git a/src/doc/src/qt3dextras-module.qdoc b/src/doc/src/qt3dextras-module.qdoc
index b9a7cc28a..facd4ef84 100644
--- a/src/doc/src/qt3dextras-module.qdoc
+++ b/src/doc/src/qt3dextras-module.qdoc
@@ -41,7 +41,7 @@
\module Qt3DExtras
\title Qt 3D Extras C++ Classes
- \brief The Qt 3D Extras modules provides a set of prebuilt elements to help
+ \brief The Qt 3D Extras module provides a set of prebuilt elements to help
you get started with Qt 3D.
This module is still in tech preview. This means it is unstable, likely to
diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.cpp b/src/plugins/sceneparsers/assimp/assimpimporter.cpp
index 6611a2529..50fd59b38 100644
--- a/src/plugins/sceneparsers/assimp/assimpimporter.cpp
+++ b/src/plugins/sceneparsers/assimp/assimpimporter.cpp
@@ -227,13 +227,13 @@ QAttribute *createAttribute(QBuffer *buffer,
return attribute;
}
-QAttribute *createAttribute(QBuffer *buffer,
- QAttribute::VertexBaseType vertexBaseType,
- uint vertexSize,
- uint count,
- uint byteOffset = 0,
- uint byteStride = 0,
- QNode *parent = nullptr)
+QAttribute *createIndexAttribute(QBuffer *buffer,
+ QAttribute::VertexBaseType vertexBaseType,
+ uint vertexSize,
+ uint count,
+ uint byteOffset = 0,
+ uint byteStride = 0,
+ QNode *parent = nullptr)
{
QAttribute *attribute = QAbstractNodeFactory::createNode<QAttribute>("QAttribute");
attribute->setBuffer(buffer);
@@ -603,7 +603,8 @@ void AssimpImporter::readSceneFile(const QString &path)
aiProcess_GenSmoothNormals|
aiProcess_FlipUVs);
if (m_scene->m_aiScene == nullptr) {
- qCWarning(AssimpImporterLog) << "Assimp scene import failed";
+ qCWarning(AssimpImporterLog) << "Assimp scene import failed" << m_scene->m_importer->GetErrorString();
+ QSceneImporter::logError(QString::fromUtf8(m_scene->m_importer->GetErrorString()));
return ;
}
parse();
@@ -828,7 +829,7 @@ QGeometryRenderer *AssimpImporter::loadMesh(uint meshIndex)
indexBuffer->setData(ibufferContent);
// Add indices attributes
- QAttribute *indexAttribute = createAttribute(indexBuffer, indiceType, 1, indices);
+ QAttribute *indexAttribute = createIndexAttribute(indexBuffer, indiceType, 1, indices);
indexAttribute->setAttributeType(QAttribute::IndexAttribute);
meshGeometry->addAttribute(indexAttribute);
diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.h b/src/plugins/sceneparsers/assimp/assimpimporter.h
index 068f6eed2..e8eda3079 100644
--- a/src/plugins/sceneparsers/assimp/assimpimporter.h
+++ b/src/plugins/sceneparsers/assimp/assimpimporter.h
@@ -143,7 +143,6 @@ private:
QHash<aiTextureType, QString> m_textureToParameterName;
QVector<Qt3DAnimation::QKeyframeAnimation *> m_animations;
QVector<Qt3DAnimation::QMorphingAnimation *> m_morphAnimations;
-// QMap<aiNode*, Light*> m_lights;
};
QDir m_sceneDir;
diff --git a/src/render/backend/buffervisitor_p.h b/src/render/backend/buffervisitor_p.h
index 7149e21ae..f7214460f 100644
--- a/src/render/backend/buffervisitor_p.h
+++ b/src/render/backend/buffervisitor_p.h
@@ -95,39 +95,7 @@ public:
Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z); Q_UNUSED(w);
}
- bool apply(const GeometryRenderer *renderer, const QString &attributeName)
- {
- if (renderer == nullptr || renderer->instanceCount() != 1) {
- return false;
- }
-
- Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId());
-
- if (!geom)
- return false;
-
- Attribute *attribute = nullptr;
-
- const auto attrIds = geom->attributes();
- for (const Qt3DCore::QNodeId attrId : attrIds) {
- attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId);
- if (attribute){
- if (attribute->name() == attributeName
- || (attributeName == QStringLiteral("default")
- && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) {
- break;
- }
- }
- attribute = nullptr;
- }
-
- if (!attribute)
- return false;
-
- return apply(attribute);
- }
-
- bool apply(Qt3DRender::Render::Attribute *attribute)
+ bool apply(Qt3DRender::Render::Attribute *attribute, Qt3DRender::Render::Attribute *indexAttribute, int drawVertexCount)
{
if (attribute->vertexBaseType() != VertexBaseType)
return false;
@@ -136,12 +104,36 @@ public:
auto data = m_manager->lookupResource<Buffer, BufferManager>(attribute->bufferId())->data();
auto buffer = BufferTypeInfo::castToType<VertexBaseType>(data, attribute->byteOffset());
- switch (dataSize) {
- case 1: traverseCoordinates1(buffer, attribute->byteStride(), attribute->count()); break;
- case 2: traverseCoordinates2(buffer, attribute->byteStride(), attribute->count()); break;
- case 3: traverseCoordinates3(buffer, attribute->byteStride(), attribute->count()); break;
- case 4: traverseCoordinates4(buffer, attribute->byteStride(), attribute->count()); break;
- default: Q_UNREACHABLE();
+
+ if (indexAttribute) {
+ auto indexData = m_manager->lookupResource<Buffer, BufferManager>(indexAttribute->bufferId())->data();
+ if (indexAttribute->vertexBaseType() == QAttribute::UnsignedShort) {
+ auto indexBuffer = BufferTypeInfo::castToType<QAttribute::UnsignedShort>(indexData, indexAttribute->byteOffset());
+ switch (dataSize) {
+ case 1: traverseCoordinates1Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break;
+ case 2: traverseCoordinates2Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break;
+ case 3: traverseCoordinates3Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break;
+ case 4: traverseCoordinates4Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break;
+ default: Q_UNREACHABLE();
+ }
+ } else {
+ auto indexBuffer = BufferTypeInfo::castToType<QAttribute::UnsignedInt>(indexData, indexAttribute->byteOffset());
+ switch (dataSize) {
+ case 1: traverseCoordinates1Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break;
+ case 2: traverseCoordinates2Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break;
+ case 3: traverseCoordinates3Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break;
+ case 4: traverseCoordinates4Indexed(buffer, attribute->byteStride(), indexBuffer, drawVertexCount); break;
+ default: Q_UNREACHABLE();
+ }
+ }
+ } else {
+ switch (dataSize) {
+ case 1: traverseCoordinates1(buffer, attribute->byteStride(), drawVertexCount); break;
+ case 2: traverseCoordinates2(buffer, attribute->byteStride(), drawVertexCount); break;
+ case 3: traverseCoordinates3(buffer, attribute->byteStride(), drawVertexCount); break;
+ case 4: traverseCoordinates4(buffer, attribute->byteStride(), drawVertexCount); break;
+ default: Q_UNREACHABLE();
+ }
}
return true;
@@ -161,42 +153,95 @@ protected:
}
}
+ template <typename Coordinate, typename IndexElem>
+ void traverseCoordinates1Indexed(Coordinate *coordinates,
+ const uint byteStride,
+ IndexElem *indices,
+ const uint count)
+ {
+ const uint stride = byteStride / sizeof(Coordinate);
+ for (uint i = 0; i < count; ++i) {
+ const uint n = stride * indices[i];
+ visit(i, coordinates[n]);
+ }
+ }
+
template <typename Coordinate>
void traverseCoordinates2(Coordinate *coordinates,
const uint byteStride,
const uint count)
{
- const uint stride = byteStride / sizeof(Coordinate);
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 2;
for (uint ndx = 0; ndx < count; ++ndx) {
visit(ndx, coordinates[0], coordinates[1]);
coordinates += stride;
}
}
+
+ template <typename Coordinate, typename IndexElem>
+ void traverseCoordinates2Indexed(Coordinate *coordinates,
+ const uint byteStride,
+ IndexElem *indices,
+ const uint count)
+ {
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 2;
+ for (uint i = 0; i < count; ++i) {
+ const uint n = stride * indices[i];
+ visit(i, coordinates[n], coordinates[n + 1]);
+ }
+ }
+
template <typename Coordinate>
void traverseCoordinates3(Coordinate *coordinates,
const uint byteStride,
const uint count)
{
- const uint stride = byteStride / sizeof(Coordinate);
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 3;
for (uint ndx = 0; ndx < count; ++ndx) {
visit(ndx, coordinates[0], coordinates[1], coordinates[2]);
coordinates += stride;
}
}
+ template <typename Coordinate, typename IndexElem>
+ void traverseCoordinates3Indexed(Coordinate *coordinates,
+ const uint byteStride,
+ IndexElem *indices,
+ const uint count)
+ {
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 3;
+ for (uint i = 0; i < count; ++i) {
+ const uint n = stride * indices[i];
+ visit(i, coordinates[n], coordinates[n + 1], coordinates[n + 2]);
+ }
+ }
+
template <typename Coordinate>
void traverseCoordinates4(Coordinate *coordinates,
const uint byteStride,
const uint count)
{
- const uint stride = byteStride / sizeof(Coordinate);
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 4;
for (uint ndx = 0; ndx < count; ++ndx) {
visit(ndx, coordinates[0], coordinates[1], coordinates[2], coordinates[3]);
coordinates += stride;
}
}
+ template <typename Coordinate, typename IndexElem>
+ void traverseCoordinates4Indexed(Coordinate *coordinates,
+ const uint byteStride,
+ IndexElem *indices,
+ const uint count)
+ {
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 4;
+ for (uint i = 0; i < count; ++i) {
+ const uint n = stride * indices[i];
+ visit(i, coordinates[n], coordinates[n + 1], coordinates[n + 2], coordinates[n + 3]);
+ }
+ }
+
NodeManagers *m_manager;
};
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index f4440a7f8..092340cf1 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -2000,7 +2000,7 @@ void Renderer::cleanGraphicsResources()
}
}
-QList<QMouseEvent> Renderer::pendingPickingEvents() const
+QList<QPair<QObject *, QMouseEvent>> Renderer::pendingPickingEvents() const
{
return m_pickEventFilter->pendingMouseEvents();
}
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index 2654b3b61..b5c8d2c4c 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -260,7 +260,7 @@ public:
inline RenderStateSet *defaultRenderState() const { return m_defaultRenderStateSet; }
- QList<QMouseEvent> pendingPickingEvents() const;
+ QList<QPair<QObject*, QMouseEvent>> pendingPickingEvents() const;
QList<QKeyEvent> pendingKeyEvents() const;
void addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId);
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index da3d551e6..9e8177c0d 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -753,14 +753,19 @@ void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, c
// ShaderData/Buffers would be handled as UBO/SSBO and would therefore
// not be in the default uniform block
if (value.valueType() == UniformValue::NodeId) {
- const Qt3DCore::QNodeId texId = *value.constData<Qt3DCore::QNodeId>();
- const Texture *tex = m_manager->textureManager()->lookupResource(texId);
- if (tex != nullptr) {
- uniformPack.setTexture(nameId, texId);
- UniformValue::Texture textureValue;
- textureValue.nodeId = texId;
- uniformPack.setUniform(nameId, UniformValue(textureValue));
+ const Qt3DCore::QNodeId *nodeIds = value.constData<Qt3DCore::QNodeId>();
+
+ const int uniformArraySize = value.byteSize() / sizeof(Qt3DCore::QNodeId);
+ for (int i = 0; i < uniformArraySize; ++i) {
+ const Qt3DCore::QNodeId texId = nodeIds[i];
+ const Texture *tex = m_manager->textureManager()->lookupResource(texId);
+ if (tex != nullptr)
+ uniformPack.setTexture(nameId, i, texId);
}
+
+ UniformValue textureValue(uniformArraySize * sizeof(int), UniformValue::TextureValue);
+ std::fill(textureValue.data<int>(), textureValue.data<int>() + uniformArraySize, -1);
+ uniformPack.setUniform(nameId, textureValue);
} else {
uniformPack.setUniform(nameId, value);
}
diff --git a/src/render/backend/shaderparameterpack.cpp b/src/render/backend/shaderparameterpack.cpp
index 01a977aee..f78e45a5e 100644
--- a/src/render/backend/shaderparameterpack.cpp
+++ b/src/render/backend/shaderparameterpack.cpp
@@ -65,17 +65,17 @@ void ShaderParameterPack::setUniform(const int glslNameId, const UniformValue &v
m_uniforms.insert(glslNameId, val);
}
-void ShaderParameterPack::setTexture(const int glslNameId, Qt3DCore::QNodeId texId)
+void ShaderParameterPack::setTexture(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId texId)
{
for (int t=0; t<m_textures.size(); ++t) {
- if (m_textures[t].glslNameId != glslNameId)
+ if (m_textures[t].glslNameId != glslNameId || m_textures[t].uniformArrayIndex != uniformArrayIndex)
continue;
m_textures[t].texId = texId;
return;
}
- m_textures.append(NamedTexture(glslNameId, texId));
+ m_textures.append(NamedTexture(glslNameId, texId, uniformArrayIndex));
}
// Contains Uniform Block Index and QNodeId of the ShaderData (UBO)
diff --git a/src/render/backend/shaderparameterpack_p.h b/src/render/backend/shaderparameterpack_p.h
index c0ab05e57..abd63a187 100644
--- a/src/render/backend/shaderparameterpack_p.h
+++ b/src/render/backend/shaderparameterpack_p.h
@@ -96,7 +96,7 @@ public:
~ShaderParameterPack();
void setUniform(const int glslNameId, const UniformValue &val);
- void setTexture(const int glslNameId, Qt3DCore::QNodeId id);
+ void setTexture(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId id);
void setUniformBuffer(BlockToUBO blockToUBO);
void setShaderStorageBuffer(BlockToSSBO blockToSSBO);
void setSubmissionUniform(const ShaderUniform &uniform);
@@ -108,13 +108,15 @@ public:
struct NamedTexture
{
NamedTexture() {}
- NamedTexture(const int nm, Qt3DCore::QNodeId t)
- : glslNameId(nm)
- , texId(t)
+ NamedTexture(const int glslNameId, Qt3DCore::QNodeId texId, int uniformArrayIndex)
+ : glslNameId(glslNameId)
+ , texId(texId)
+ , uniformArrayIndex(uniformArrayIndex)
{ }
int glslNameId;
Qt3DCore::QNodeId texId;
+ int uniformArrayIndex;
};
inline QVector<NamedTexture> textures() const { return m_textures; }
diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp
index 4a05d8f19..87ba7bde9 100644
--- a/src/render/backend/trianglesvisitor.cpp
+++ b/src/render/backend/trianglesvisitor.cpp
@@ -85,8 +85,8 @@ void traverseTrianglesIndexed(index *indices,
TrianglesVisitor* visitor)
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
Vector3D abc[3];
@@ -111,8 +111,8 @@ void traverseTriangles(vertex *vertices,
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
Vector3D abc[3];
@@ -147,8 +147,8 @@ void traverseTriangleStripIndexed(index *indices,
TrianglesVisitor* visitor)
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
Vector3D abc[3];
@@ -178,8 +178,8 @@ void traverseTriangleStrip(vertex *vertices,
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
Vector3D abc[3];
@@ -204,8 +204,8 @@ void traverseTriangleFanIndexed(index *indices,
const BufferInfo &vertexInfo,
TrianglesVisitor* visitor)
{
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
Vector3D abc[3];
@@ -234,8 +234,8 @@ void traverseTriangleFan(vertex *vertices,
const BufferInfo &vertexInfo,
TrianglesVisitor* visitor)
{
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
Vector3D abc[3];
@@ -268,8 +268,8 @@ void traverseTriangleAdjacencyIndexed(index *indices,
TrianglesVisitor* visitor)
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
uint ndx[3];
Vector3D abc[3];
@@ -294,8 +294,8 @@ void traverseTriangleAdjacency(Vertex *vertices,
{
uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+ const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(Vertex) : maxVerticesDataSize;
uint ndx[3];
Vector3D abc[3];
@@ -315,7 +315,7 @@ void traverseTriangleAdjacency(Vertex *vertices,
template<typename Coordinate>
Vector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint index)
{
- const uint stride = info.byteStride / sizeof(Coordinate);
+ const uint stride = info.byteStride ? info.byteStride / sizeof(Coordinate) : info.dataSize;
Vector4D ret(0, 0, 0, 1.0f);
coordinates += stride * index;
for (uint e = 0; e < info.dataSize; ++e)
diff --git a/src/render/backend/uniform.cpp b/src/render/backend/uniform.cpp
index aedba5375..41ee24967 100644
--- a/src/render/backend/uniform.cpp
+++ b/src/render/backend/uniform.cpp
@@ -56,10 +56,12 @@ int byteSizeForMetaType(int type)
{
if (type == qMatrix4x4TypeId)
return sizeof(Matrix4x4);
- if (type == qVector3DTypeId)
+ if (type == qVector3DTypeId)
return sizeof(Vector3D);
- if (type == qVector4DTypeId)
+ if (type == qVector4DTypeId)
return sizeof(Vector4D);
+ if (type == qNodeIdTypeId)
+ return sizeof(Qt3DCore::QNodeId);
switch (type) {
case QMetaType::Bool:
@@ -230,6 +232,11 @@ UniformValue UniformValue::fromVariant(const QVariant &variant)
break;
const int listEntryType = variants.first().userType();
+
+ // array of textures
+ if (listEntryType == qNodeIdTypeId)
+ v.m_valueType = NodeId;
+
const int stride = byteSizeForMetaType(listEntryType) / sizeof(float);
// Resize v.m_data
v.m_data.resize(stride * variants.size());
diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h
index 213cf2606..e31aaa609 100644
--- a/src/render/backend/uniform_p.h
+++ b/src/render/backend/uniform_p.h
@@ -114,11 +114,6 @@ public:
BufferValue
};
- struct Texture {
- int textureId = 0; // Set first so that glUniform1iv will work
- Qt3DCore::QNodeId nodeId;
- };
-
// UniformValue implicitely converts doubles to floats to ensure
// correct rendering behavior for the cases where Qt3D parameters created from
// a double or QVariant(double) are used to fill uniform values that in reality
@@ -177,6 +172,13 @@ public:
}
}
+ // Reserve data to be filled in later
+ UniformValue(int byteSize, ValueType valueType)
+ : m_data(byteSize / sizeof(float))
+ , m_valueType(valueType)
+ {
+ }
+
// For nodes which will later be replaced by a Texture or Buffer
UniformValue(Qt3DCore::QNodeId id)
: UniformValue()
@@ -185,14 +187,6 @@ public:
memcpy(m_data.data(), &id, sizeof(Qt3DCore::QNodeId));
}
- // For textures
- UniformValue(UniformValue::Texture t)
- : UniformValue()
- {
- m_valueType = TextureValue;
- memcpy(m_data.data(), &t, sizeof(Texture));
- }
-
ValueType valueType() const { return m_valueType; }
UniformType storedType() const { return m_storedType; }
diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp
index 298f6bf91..5c3128f30 100644
--- a/src/render/graphicshelpers/graphicscontext.cpp
+++ b/src/render/graphicshelpers/graphicscontext.cpp
@@ -499,14 +499,14 @@ void GraphicsContext::introspectShaderInterface(Shader *shader, QOpenGLShaderPro
void GraphicsContext::loadShader(Shader *shader, ShaderManager *manager)
{
- QOpenGLShaderProgram *shaderProgram = m_shaderCache.getShaderProgramAndAddRef(shader->dna(), shader->peerId());
- if (!shaderProgram) {
+ bool wasPresent = false;
+ QOpenGLShaderProgram *shaderProgram = m_shaderCache.getShaderProgramAndAddRef(shader->dna(), shader->peerId(), &wasPresent);
+ if (!shaderProgram && !wasPresent) {
// No matching QOpenGLShader in the cache so create one
shaderProgram = createShaderProgram(shader);
- // Store in cache
- if (shaderProgram)
- m_shaderCache.insert(shader->dna(), shader->peerId(), shaderProgram);
+ // Store in cache (even when failed and shaderProgram is null)
+ m_shaderCache.insert(shader->dna(), shader->peerId(), shaderProgram);
}
// Ensure the Shader node knows about the program interface
@@ -1213,7 +1213,7 @@ bool GraphicsContext::setParameters(ShaderParameterPack &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;