summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2015-12-10 15:58:05 +0000
committerMike Krus <mike.krus@kdab.com>2016-01-25 14:13:13 +0000
commit28ec1ca1883e0fe9b8b0e0de4049564ae652bd90 (patch)
tree3722809fc54b75d08b08fb68bd5d9d56fbe24342
parent4ad00b344bc79e34f2ba2f8355e65c7948791389 (diff)
Refactor picking to use one thread per entity
Added triangle visitor by refactor the triangle volume extractor Added ability to do a ray intersection with a single volume without using a thread Added entity collector Use one thread for each entity Ignore entities that don’t have a pick object Removed list of triangle volumes stored on each entity Use triangle visitor to test each triangle by creating a single volume on the stack Added triangle and 3 vertex index to the pick event Change-Id: Id3fd53549bf3ea07805426ef868df174f30e176b Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--examples/qt3d/bigmodel-qml/MyEntity.qml7
-rw-r--r--examples/qt3d/bigmodel-qml/main.qml1
-rw-r--r--src/render/backend/render-backend.pri2
-rw-r--r--src/render/backend/trianglesextractor.cpp447
-rw-r--r--src/render/backend/trianglesextractor_p.h13
-rw-r--r--src/render/backend/trianglesvisitor.cpp518
-rw-r--r--src/render/backend/trianglesvisitor_p.h91
-rw-r--r--src/render/frontend/qrenderaspect.cpp13
-rw-r--r--src/render/jobs/calcboundingvolumejob.cpp2
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp440
-rw-r--r--src/render/jobs/pickboundingvolumejob_p.h13
-rw-r--r--src/render/picking/qpickevent.cpp35
-rw-r--r--src/render/picking/qpickevent.h11
-rw-r--r--src/render/raycasting/qabstractcollisionqueryservice_p.h3
-rw-r--r--src/render/raycasting/qcollisionqueryresult_p.h2
-rw-r--r--src/render/raycasting/qraycastingservice.cpp20
-rw-r--r--src/render/raycasting/qraycastingservice_p.h4
17 files changed, 943 insertions, 679 deletions
diff --git a/examples/qt3d/bigmodel-qml/MyEntity.qml b/examples/qt3d/bigmodel-qml/MyEntity.qml
index df0dbd13d..9b2b32c5a 100644
--- a/examples/qt3d/bigmodel-qml/MyEntity.qml
+++ b/examples/qt3d/bigmodel-qml/MyEntity.qml
@@ -36,15 +36,20 @@
import Qt3D.Core 2.0
import Qt3D.Render 2.0
+import Qt3D.Input 2.0
Entity {
id: root
+ property string name: "Entity"
property alias position: transform.translation
property alias diffuse: material.diffuse
components: [
Transform { id: transform },
SphereMesh { radius: 2 },
- PhongMaterial { id: material }
+ PhongMaterial { id: material },
+ ObjectPicker {
+ onClicked: console.log("Clicked", root.name, pick.distance, pick.triangleIndex)
+ }
]
}
diff --git a/examples/qt3d/bigmodel-qml/main.qml b/examples/qt3d/bigmodel-qml/main.qml
index 18597f1f5..1266f8e9c 100644
--- a/examples/qt3d/bigmodel-qml/main.qml
+++ b/examples/qt3d/bigmodel-qml/main.qml
@@ -81,6 +81,7 @@ Entity {
model: entityModel
delegate: MyEntity {
id: myEntity
+ name: "E" + index
property real _lightness: 0.2 + 0.7 / collection._rows * Math.floor(index / collection.cols)
property real _hue: (index % collection.cols) / collection.cols
position: Qt.vector3d(collection.spacing * (index % collection.cols - 0.5 * (collection.cols - 1)),
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index 0b7efa5e7..5d2018b7d 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -27,6 +27,7 @@ HEADERS += \
$$PWD/triangleboundingvolume_p.h \
$$PWD/openglvertexarrayobject_p.h \
$$PWD/trianglesextractor_p.h \
+ $$PWD/trianglesvisitor_p.h \
$$PWD/abstractrenderer_p.h \
$$PWD/computejob_p.h \
$$PWD/renderersettings_p.h
@@ -53,5 +54,6 @@ SOURCES += \
$$PWD/nodemanagers.cpp \
$$PWD/triangleboundingvolume.cpp \
$$PWD/trianglesextractor.cpp \
+ $$PWD/trianglesvisitor.cpp \
$$PWD/computejob.cpp \
$$PWD/renderersettings.cpp
diff --git a/src/render/backend/trianglesextractor.cpp b/src/render/backend/trianglesextractor.cpp
index 85eba29df..9e63c1c1e 100644
--- a/src/render/backend/trianglesextractor.cpp
+++ b/src/render/backend/trianglesextractor.cpp
@@ -35,11 +35,13 @@
****************************************************************************/
#include "trianglesextractor_p.h"
+#include <Qt3DCore/qentity.h>
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DRender/private/geometryrenderer_p.h>
+#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/geometry_p.h>
#include <Qt3DRender/private/attribute_p.h>
#include <Qt3DRender/private/buffer_p.h>
@@ -51,448 +53,23 @@ namespace Qt3DRender {
namespace Render {
-namespace {
-
-bool isTriangleBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) Q_DECL_NOEXCEPT
-{
- switch (type) {
- case Qt3DRender::QGeometryRenderer::Triangles:
- case Qt3DRender::QGeometryRenderer::TriangleStrip:
- case Qt3DRender::QGeometryRenderer::TriangleFan:
- case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
- case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency:
- return true;
- default:
- return false;
- }
-}
-
-struct BufferInfo
-{
- BufferInfo()
- : type(QAttribute::DataType::Float)
- , dataSize(0)
- , count(0)
- , byteStride(0)
- , byteOffset(0)
- {}
-
- QByteArray data;
- QAttribute::DataType type;
- uint dataSize;
- uint count;
- uint byteStride;
- uint byteOffset;
-};
-
-// TO DO: Add methods for triangle strip adjacency
-// What about primitive restart ?
-
-// indices, vertices are already offset
-template<typename index, typename vertex>
-QVector<QBoundingVolume *> traverseTrianglesIndexed(index *indices,
- vertex *vertices,
- const BufferInfo &indexInfo,
- const BufferInfo &vertexInfo,
- const Qt3DCore::QNodeId id)
-{
- QVector<QBoundingVolume *> tris;
- uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
- const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
-
- QVector3D abc[3];
- while (i < indexInfo.count) {
- for (uint u = 0; u < 3; ++u) {
- uint idx = indices[i + u] * verticesStride;
- for (uint j = 0; j < maxVerticesDataSize; ++j) {
- abc[u][j] = vertices[idx + j];
- }
- }
- tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0]));
- i += 3;
- }
-
- return tris;
-}
-
-// vertices are already offset
-template<typename vertex>
-QVector<QBoundingVolume *> traverseTriangles(vertex *vertices,
- const BufferInfo &vertexInfo,
- const Qt3DCore::QNodeId id)
-{
- QVector<QBoundingVolume *> tris;
- uint i = 0;
-
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
- const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
-
- QVector3D abc[3];
- while (i < vertexInfo.count) {
- for (uint u = 0; u < 3; ++u) {
- uint idx = (i + u) * verticesStride;
- for (uint j = 0; j < maxVerticesDataSize; ++j) {
- abc[u][j] = vertices[idx + j];
- }
- }
- tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0]));
- i += 3;
- }
- return tris;
-}
-
-// indices, vertices are already offset
-template<typename index, typename vertex>
-QVector<QBoundingVolume *> traverseTriangleStripIndexed(index *indices,
- vertex *vertices,
- const BufferInfo &indexInfo,
- const BufferInfo &vertexInfo,
- const Qt3DCore::QNodeId id)
-{
- QVector<QBoundingVolume *> tris;
- uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
- const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
-
- QVector3D abc[3];
- while (i < indexInfo.count) {
- for (uint u = 0; u < 3; ++u) {
- uint idx = indices[i + u] * verticesStride;
- for (uint j = 0; j < maxVerticesDataSize; ++j) {
- abc[u][j] = vertices[idx + j];
- }
- }
- tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0]));
- ++i;
- }
-
- return tris;
-}
-
-// vertices are already offset
-template<typename vertex>
-QVector<QBoundingVolume *> traverseTriangleStrip(vertex *vertices,
- const BufferInfo &vertexInfo,
- const Qt3DCore::QNodeId id)
-{
- QVector<QBoundingVolume *> tris;
- uint i = 0;
-
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
- const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
-
- QVector3D abc[3];
- while (i < vertexInfo.count) {
- for (uint u = 0; u < 3; ++u) {
- uint idx = (i + u) * verticesStride;
- for (uint j = 0; j < maxVerticesDataSize; ++j) {
- abc[u][j] = vertices[idx + j];
- }
- }
- tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0]));
- ++i;
- }
- return tris;
-}
-
-// indices, vertices are already offset
-template<typename index, typename vertex>
-QVector<QBoundingVolume *> traverseTriangleFanIndexed(index *indices,
- vertex *vertices,
- const BufferInfo &indexInfo,
- const BufferInfo &vertexInfo,
- const Qt3DCore::QNodeId id)
-{
- QVector<QBoundingVolume *> tris;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
- const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
-
- QVector3D abc[3];
-
- for (uint j = 0; j < maxVerticesDataSize; ++j) {
- abc[0][j] = vertices[static_cast<int>(indices[0]) * verticesStride + j];
- }
-
- uint i = 1;
- while (i < indexInfo.count) {
- for (uint u = 0; u < 2; ++u) {
- uint idx = indices[i + u] * verticesStride;
- for (uint j = 0; j < maxVerticesDataSize; ++j) {
- abc[u + 1][j] = vertices[idx + j];
- }
- }
- tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0]));
- i += 2;
- }
-
- return tris;
-}
-
-// vertices are already offset
-template<typename vertex>
-QVector<QBoundingVolume *> traverseTriangleFan(vertex *vertices,
- const BufferInfo &vertexInfo,
- const Qt3DCore::QNodeId id)
-{
- QVector<QBoundingVolume *> tris;
-
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
- const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
-
- QVector3D abc[3];
-
- for (uint j = 0; j < maxVerticesDataSize; ++j) {
- abc[0][j] = vertices[j];
- }
-
- uint i = 1;
- while (i < vertexInfo.count) {
- for (uint u = 0; u < 2; ++u) {
- uint idx = (i + u) * verticesStride;
- for (uint j = 0; j < maxVerticesDataSize; ++j) {
- abc[u + 1][j] = vertices[idx + j];
- }
- }
- tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0]));
- i += 2;
- }
- return tris;
-}
-
-// indices, vertices are already offset
-template<typename index, typename vertex>
-QVector<QBoundingVolume *> traverseTriangleAdjacencyIndexed(index *indices,
- vertex *vertices,
- const BufferInfo &indexInfo,
- const BufferInfo &vertexInfo,
- const Qt3DCore::QNodeId id)
-{
- QVector<QBoundingVolume *> tris;
- uint i = 0;
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
- const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
-
- QVector3D abc[3];
- while (i < indexInfo.count) {
- for (uint u = 0; u < 6; u += 2) {
- uint idx = indices[i + u] * verticesStride;
- for (uint j = 0; j < maxVerticesDataSize; ++j) {
- abc[u / 2][j] = vertices[idx + j];
- }
- }
- tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0]));
- i += 6;
- }
-
- return tris;
-}
-
-// vertices are already offset
-template<typename vertex>
-QVector<QBoundingVolume *> traverseTriangleAdjacency(vertex *vertices,
- const BufferInfo &vertexInfo,
- const Qt3DCore::QNodeId id)
-{
- QVector<QBoundingVolume *> tris;
- uint i = 0;
-
- const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
- const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
-
- QVector3D abc[3];
- while (i < vertexInfo.count) {
- for (uint u = 0; u < 6; u += 2) {
- uint idx = (i + u) * verticesStride;
- for (uint j = 0; j < maxVerticesDataSize; ++j) {
- abc[u / 2][j] = vertices[idx + j];
- }
- }
- tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0]));
- i += 6;
- }
- return tris;
-}
-
-
-template <QAttribute::DataType> struct EnumToType;
-template <> struct EnumToType<QAttribute::Byte> { typedef const char type; };
-template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; };
-template <> struct EnumToType<QAttribute::Short> { typedef const short type; };
-template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; };
-template <> struct EnumToType<QAttribute::Int> { typedef const int type; };
-template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; };
-template <> struct EnumToType<QAttribute::Float> { typedef const float type; };
-template <> struct EnumToType<QAttribute::Double> { typedef const double type; };
-
-template<QAttribute::DataType v>
-typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset)
-{
- return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
-}
-
-template<typename ReturnType, typename Func>
-QVector<QBoundingVolume *> processBuffer(const BufferInfo &info, Func &f)
-{
- switch (info.type) {
- case QAttribute::Byte: return f(info, castToType<QAttribute::Byte>(info.data, info.byteOffset));
- case QAttribute::UnsignedByte: return f(info, castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset));
- case QAttribute::Short: return f(info, castToType<QAttribute::Short>(info.data, info.byteOffset));
- case QAttribute::UnsignedShort: return f(info, castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset));
- case QAttribute::Int: return f(info, castToType<QAttribute::Int>(info.data, info.byteOffset));
- case QAttribute::UnsignedInt: return f(info, castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset));
- case QAttribute::Float: return f(info, castToType<QAttribute::Float>(info.data, info.byteOffset));
- case QAttribute::Double: return f(info, castToType<QAttribute::Double>(info.data, info.byteOffset));
- default:
- return ReturnType();
- }
-}
-
-template<typename Index, typename ReturnType>
-struct IndexedVertexExecutor
-{
- template<typename Vertex>
- ReturnType operator ()(const BufferInfo &vertexInfo, Vertex * vertices)
- {
- switch (primitiveType) {
- case Qt3DRender::QGeometryRenderer::Triangles:
- return traverseTrianglesIndexed(indices, vertices, indexBufferInfo, vertexInfo, id);
- case Qt3DRender::QGeometryRenderer::TriangleStrip:
- return traverseTriangleStripIndexed(indices, vertices, indexBufferInfo, vertexInfo, id);
- case Qt3DRender::QGeometryRenderer::TriangleFan:
- return traverseTriangleFanIndexed(indices, vertices, indexBufferInfo, vertexInfo, id);
- case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
- return traverseTriangleAdjacencyIndexed(indices, vertices, indexBufferInfo, vertexInfo, id);
- case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency:
- default:
- return ReturnType();
- }
- }
-
- BufferInfo indexBufferInfo;
- Index *indices;
- Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
- Qt3DCore::QNodeId id;
-};
-
-template<typename ReturnType>
-struct IndexExecutor
-{
- BufferInfo vertexBufferInfo;
-
- template<typename Index>
- ReturnType operator ()( const BufferInfo &indexInfo, Index *indices)
- {
- IndexedVertexExecutor<Index, ReturnType> exec;
- exec.primitiveType = primitiveType;
- exec.indices = indices;
- exec.indexBufferInfo = indexInfo;
- exec.id = id;
- return processBuffer<ReturnType>(vertexBufferInfo, exec);
- }
-
- Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
- Qt3DCore::QNodeId id;
-};
-
-template<typename ReturnType>
-struct VertexExecutor
-{
- template<typename Vertex>
- ReturnType operator ()(const BufferInfo &vertexInfo, Vertex *vertices)
- {
- switch (primitiveType) {
- case Qt3DRender::QGeometryRenderer::Triangles:
- return traverseTriangles(vertices, vertexInfo, id);
- case Qt3DRender::QGeometryRenderer::TriangleStrip:
- return traverseTriangleStrip(vertices, vertexInfo, id);
- case Qt3DRender::QGeometryRenderer::TriangleFan:
- return traverseTriangleFan(vertices, vertexInfo, id);
- case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
- return traverseTriangleAdjacency(vertices, vertexInfo, id);
- case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency:
- default:
- return ReturnType();
- }
- }
-
- Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
- Qt3DCore::QNodeId id;
-};
-
-} // anonymous
-
TrianglesExtractor::TrianglesExtractor(GeometryRenderer *renderer, NodeManagers *manager)
- : m_renderer(renderer)
- , m_manager(manager)
+ : TrianglesVisitor(manager)
+ , m_renderer(renderer)
{
}
QVector<QBoundingVolume *> TrianglesExtractor::extract(const Qt3DCore::QNodeId id)
{
- if (m_renderer && m_renderer->instanceCount() == 1 && isTriangleBased(m_renderer->primitiveType())) {
- Attribute *positionAttribute = Q_NULLPTR;
- Attribute *indexAttribute = Q_NULLPTR;
- Buffer *positionBuffer = Q_NULLPTR;
- Buffer *indexBuffer = Q_NULLPTR;
- Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(m_renderer->geometryId());
-
- if (geom) {
- Qt3DRender::Render::Attribute *attribute = Q_NULLPTR;
- Q_FOREACH (const Qt3DCore::QNodeId attrId, geom->attributes()) {
- attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId);
- if (attribute){
- if (attribute->name() == QAttribute::defaultPositionAttributeName())
- positionAttribute = attribute;
- else if (attribute->attributeType() == QAttribute::IndexAttribute)
- indexAttribute = attribute;
- }
- }
-
- if (positionAttribute)
- positionBuffer = m_manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId());
- if (indexAttribute)
- indexBuffer = m_manager->lookupResource<Buffer, BufferManager>(indexAttribute->bufferId());
-
- if (positionBuffer) {
-
- BufferInfo vertexBufferInfo;
- vertexBufferInfo.data = positionBuffer->data();
- vertexBufferInfo.type = positionAttribute->dataType();
- vertexBufferInfo.byteOffset = positionAttribute->byteOffset();
- vertexBufferInfo.byteStride = positionAttribute->byteStride();
- vertexBufferInfo.dataSize = positionAttribute->dataSize();
- vertexBufferInfo.count = positionAttribute->count();
-
- if (indexBuffer) { // Indexed
-
- BufferInfo indexBufferInfo;
- indexBufferInfo.data = indexBuffer->data();
- indexBufferInfo.type = indexAttribute->dataType();
- indexBufferInfo.byteOffset = indexAttribute->byteOffset();
- indexBufferInfo.byteStride = indexAttribute->byteStride();
- indexBufferInfo.count = indexAttribute->count();
-
- IndexExecutor<QVector<QBoundingVolume *> > executor;
- executor.vertexBufferInfo = vertexBufferInfo;
- executor.primitiveType = m_renderer->primitiveType();
- executor.id = id;
-
- return processBuffer<QVector<QBoundingVolume *> >(indexBufferInfo, executor);
-
- } else { // Non Indexed
-
- // Check into which type the buffer needs to be casted
- VertexExecutor<QVector<QBoundingVolume *> > executor;
- executor.primitiveType = m_renderer->primitiveType();
- executor.id = id;
+ qDeleteAll(m_volumes);
+ apply(m_renderer, id);
+ return m_volumes;
+}
- return processBuffer<QVector<QBoundingVolume *> >(vertexBufferInfo, executor);
- }
- }
- }
- }
- return QVector<QBoundingVolume *>();
+void TrianglesExtractor::visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c)
+{
+ Q_UNUSED(andx); Q_UNUSED(bndx); Q_UNUSED(cndx);
+ m_volumes.push_back(new TriangleBoundingVolume(m_nodeId, a, b, c));
}
} // namespace Render
diff --git a/src/render/backend/trianglesextractor_p.h b/src/render/backend/trianglesextractor_p.h
index 7353278fe..0cb6d9b40 100644
--- a/src/render/backend/trianglesextractor_p.h
+++ b/src/render/backend/trianglesextractor_p.h
@@ -48,7 +48,7 @@
// We mean it.
//
-#include <Qt3DCore/qnodeid.h>
+#include "trianglesvisitor_p.h"
QT_BEGIN_NAMESPACE
@@ -58,10 +58,7 @@ class QBoundingVolume;
namespace Render {
-class GeometryRenderer;
-class NodeManagers;
-
-class Q_AUTOTEST_EXPORT TrianglesExtractor
+class Q_AUTOTEST_EXPORT TrianglesExtractor : private TrianglesVisitor
{
public:
explicit TrianglesExtractor(GeometryRenderer *renderer,
@@ -70,8 +67,12 @@ public:
QVector<QBoundingVolume *> extract(const Qt3DCore::QNodeId id);
private:
+ void visit(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b,
+ uint cndx, const QVector3D &c) Q_DECL_OVERRIDE;
+
GeometryRenderer *m_renderer;
- NodeManagers *m_manager;
+ QVector<QBoundingVolume *> m_volumes;
};
} // namespace Render
diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp
new file mode 100644
index 000000000..de4f833d5
--- /dev/null
+++ b/src/render/backend/trianglesvisitor.cpp
@@ -0,0 +1,518 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Paul Lemire paul.lemire350@gmail.com
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "trianglesvisitor_p.h"
+#include <Qt3DCore/qentity.h>
+#include <Qt3DRender/qgeometryrenderer.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/buffermanager_p.h>
+#include <Qt3DRender/private/geometryrenderer_p.h>
+#include <Qt3DRender/private/geometryrenderermanager_p.h>
+#include <Qt3DRender/private/geometry_p.h>
+#include <Qt3DRender/private/attribute_p.h>
+#include <Qt3DRender/private/buffer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+namespace {
+
+bool isTriangleBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) Q_DECL_NOEXCEPT
+{
+ switch (type) {
+ case Qt3DRender::QGeometryRenderer::Triangles:
+ case Qt3DRender::QGeometryRenderer::TriangleStrip:
+ case Qt3DRender::QGeometryRenderer::TriangleFan:
+ case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
+ case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency:
+ return true;
+ default:
+ return false;
+ }
+}
+
+struct BufferInfo
+{
+ BufferInfo()
+ : type(QAttribute::DataType::Float)
+ , dataSize(0)
+ , count(0)
+ , byteStride(0)
+ , byteOffset(0)
+ {}
+
+ QByteArray data;
+ QAttribute::DataType type;
+ uint dataSize;
+ uint count;
+ uint byteStride;
+ uint byteOffset;
+};
+
+// TO DO: Add methods for triangle strip adjacency
+// What about primitive restart ?
+
+// indices, vertices are already offset
+template<typename index, typename vertex>
+void traverseTrianglesIndexed(index *indices,
+ vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ TrianglesVisitor* visitor)
+{
+ uint i = 0;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[3];
+ QVector3D abc[3];
+ while (i < indexInfo.count) {
+ for (uint u = 0; u < 3; ++u) {
+ uint idx = indices[i + u] * verticesStride;
+ ndx[u] = idx;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]);
+ i += 3;
+ }
+}
+
+// vertices are already offset
+template<typename vertex>
+void traverseTriangles(vertex *vertices,
+ const BufferInfo &vertexInfo,
+ TrianglesVisitor* visitor)
+{
+ uint i = 0;
+
+ const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[3];
+ QVector3D abc[3];
+ while (i < vertexInfo.count) {
+ for (uint u = 0; u < 3; ++u) {
+ uint idx = (i + u) * verticesStride;
+ ndx[u] = idx;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]);
+ i += 3;
+ }
+}
+
+// indices, vertices are already offset
+template<typename index, typename vertex>
+void traverseTriangleStripIndexed(index *indices,
+ vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ TrianglesVisitor* visitor)
+{
+ uint i = 0;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[3];
+ QVector3D abc[3];
+ while (i < indexInfo.count) {
+ for (uint u = 0; u < 3; ++u) {
+ uint idx = indices[i + u] * verticesStride;
+ ndx[u] = idx;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]);
+ ++i;
+ }
+}
+
+// vertices are already offset
+template<typename vertex>
+void traverseTriangleStrip(vertex *vertices,
+ const BufferInfo &vertexInfo,
+ TrianglesVisitor* visitor)
+{
+ uint i = 0;
+
+ const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[3];
+ QVector3D abc[3];
+ while (i < vertexInfo.count) {
+ for (uint u = 0; u < 3; ++u) {
+ uint idx = (i + u) * verticesStride;
+ ndx[u] = idx;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[2], abc[0]);
+ ++i;
+ }
+}
+
+// indices, vertices are already offset
+template<typename index, typename vertex>
+void traverseTriangleFanIndexed(index *indices,
+ vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ TrianglesVisitor* visitor)
+{
+ const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[3];
+ QVector3D abc[3];
+
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[0][j] = vertices[static_cast<int>(indices[0]) * verticesStride + j];
+ }
+
+ uint i = 1;
+ while (i < indexInfo.count) {
+ for (uint u = 0; u < 2; ++u) {
+ uint idx = indices[i + u] * verticesStride;
+ ndx[i] = idx;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u + 1][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]);
+ i += 2;
+ }
+}
+
+// vertices are already offset
+template<typename vertex>
+void traverseTriangleFan(vertex *vertices,
+ const BufferInfo &vertexInfo,
+ TrianglesVisitor* visitor)
+{
+ const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[3];
+ QVector3D abc[3];
+
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[0][j] = vertices[j];
+ }
+
+ uint i = 1;
+ while (i < vertexInfo.count) {
+ for (uint u = 0; u < 2; ++u) {
+ uint idx = (i + u) * verticesStride;
+ ndx[u] = idx;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u + 1][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]);
+ i += 2;
+ }
+}
+
+// indices, vertices are already offset
+template<typename index, typename vertex>
+void traverseTriangleAdjacencyIndexed(index *indices,
+ vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ TrianglesVisitor* visitor)
+{
+ uint i = 0;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[3];
+ QVector3D abc[3];
+ while (i < indexInfo.count) {
+ for (uint u = 0; u < 6; u += 2) {
+ uint idx = indices[i + u] * verticesStride;
+ ndx[u] = idx;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u / 2][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]);
+ i += 6;
+ }
+}
+
+// vertices are already offset
+template<typename Vertex>
+void traverseTriangleAdjacency(Vertex *vertices,
+ const BufferInfo &vertexInfo,
+ TrianglesVisitor* visitor)
+{
+ uint i = 0;
+
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[3];
+ QVector3D abc[3];
+ while (i < vertexInfo.count) {
+ for (uint u = 0; u < 6; u += 2) {
+ uint idx = (i + u) * verticesStride;
+ ndx[u] = idx;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u / 2][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]);
+ i += 6;
+ }
+}
+
+
+template <QAttribute::DataType> struct EnumToType;
+template <> struct EnumToType<QAttribute::Byte> { typedef const char type; };
+template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; };
+template <> struct EnumToType<QAttribute::Short> { typedef const short type; };
+template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; };
+template <> struct EnumToType<QAttribute::Int> { typedef const int type; };
+template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; };
+template <> struct EnumToType<QAttribute::Float> { typedef const float type; };
+template <> struct EnumToType<QAttribute::Double> { typedef const double type; };
+
+template<QAttribute::DataType v>
+typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset)
+{
+ return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
+}
+
+template<typename Func>
+void processBuffer(const BufferInfo &info, Func &f)
+{
+ switch (info.type) {
+ case QAttribute::Byte: f(info, castToType<QAttribute::Byte>(info.data, info.byteOffset));
+ return;
+ case QAttribute::UnsignedByte: f(info, castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Short: f(info, castToType<QAttribute::Short>(info.data, info.byteOffset));
+ return;
+ case QAttribute::UnsignedShort: f(info, castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Int: f(info, castToType<QAttribute::Int>(info.data, info.byteOffset));
+ return;
+ case QAttribute::UnsignedInt: f(info, castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Float: f(info, castToType<QAttribute::Float>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Double: f(info, castToType<QAttribute::Double>(info.data, info.byteOffset));
+ return;
+ default:
+ return;
+ }
+}
+
+template<typename Index>
+struct IndexedVertexExecutor
+{
+ template<typename Vertex>
+ void operator ()(const BufferInfo &vertexInfo, Vertex * vertices)
+ {
+ switch (primitiveType) {
+ case Qt3DRender::QGeometryRenderer::Triangles:
+ traverseTrianglesIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::TriangleStrip:
+ traverseTriangleStripIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::TriangleFan:
+ traverseTriangleFanIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
+ traverseTriangleAdjacencyIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: // fall through
+ default:
+ return;
+ }
+ }
+
+ BufferInfo indexBufferInfo;
+ Index *indices;
+ Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
+ TrianglesVisitor* visitor;
+};
+
+struct IndexExecutor
+{
+ BufferInfo vertexBufferInfo;
+
+ template<typename Index>
+ void operator ()( const BufferInfo &indexInfo, Index *indices)
+ {
+ IndexedVertexExecutor<Index> exec;
+ exec.primitiveType = primitiveType;
+ exec.indices = indices;
+ exec.indexBufferInfo = indexInfo;
+ exec.visitor = visitor;
+ processBuffer(vertexBufferInfo, exec);
+ }
+
+ Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
+ TrianglesVisitor* visitor;
+};
+
+struct VertexExecutor
+{
+ template<typename Vertex>
+ void operator ()(const BufferInfo &vertexInfo, Vertex *vertices)
+ {
+ switch (primitiveType) {
+ case Qt3DRender::QGeometryRenderer::Triangles:
+ traverseTriangles(vertices, vertexInfo, visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::TriangleStrip:
+ traverseTriangleStrip(vertices, vertexInfo, visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::TriangleFan:
+ traverseTriangleFan(vertices, vertexInfo, visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
+ traverseTriangleAdjacency(vertices, vertexInfo, visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: // fall through
+ default:
+ return;
+ }
+ }
+
+ Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
+ TrianglesVisitor* visitor;
+};
+
+} // anonymous
+
+
+TrianglesVisitor::~TrianglesVisitor()
+{
+
+}
+
+void TrianglesVisitor::apply(const Qt3DCore::QEntity *entity)
+{
+ GeometryRenderer *renderer = m_manager->geometryRendererManager()->lookupResource(entity->id());
+ apply(renderer, entity->id());
+}
+
+void TrianglesVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id)
+{
+ m_nodeId = id;
+ if (renderer && renderer->instanceCount() == 1 && isTriangleBased(renderer->primitiveType())) {
+ Attribute *positionAttribute = Q_NULLPTR;
+ Attribute *indexAttribute = Q_NULLPTR;
+ Buffer *positionBuffer = Q_NULLPTR;
+ Buffer *indexBuffer = Q_NULLPTR;
+ Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId());
+
+ if (geom) {
+ Qt3DRender::Render::Attribute *attribute = Q_NULLPTR;
+ Q_FOREACH (const Qt3DCore::QNodeId attrId, geom->attributes()) {
+ attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId);
+ if (attribute){
+ if (attribute->name() == QAttribute::defaultPositionAttributeName())
+ positionAttribute = attribute;
+ else if (attribute->attributeType() == QAttribute::IndexAttribute)
+ indexAttribute = attribute;
+ }
+ }
+
+ if (positionAttribute)
+ positionBuffer = m_manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId());
+ if (indexAttribute)
+ indexBuffer = m_manager->lookupResource<Buffer, BufferManager>(indexAttribute->bufferId());
+
+ if (positionBuffer) {
+
+ BufferInfo vertexBufferInfo;
+ vertexBufferInfo.data = positionBuffer->data();
+ vertexBufferInfo.type = positionAttribute->dataType();
+ vertexBufferInfo.byteOffset = positionAttribute->byteOffset();
+ vertexBufferInfo.byteStride = positionAttribute->byteStride();
+ vertexBufferInfo.dataSize = positionAttribute->dataSize();
+ vertexBufferInfo.count = positionAttribute->count();
+
+ if (indexBuffer) { // Indexed
+
+ BufferInfo indexBufferInfo;
+ indexBufferInfo.data = indexBuffer->data();
+ indexBufferInfo.type = indexAttribute->dataType();
+ indexBufferInfo.byteOffset = indexAttribute->byteOffset();
+ indexBufferInfo.byteStride = indexAttribute->byteStride();
+ indexBufferInfo.count = indexAttribute->count();
+
+ IndexExecutor executor;
+ executor.vertexBufferInfo = vertexBufferInfo;
+ executor.primitiveType = renderer->primitiveType();
+ executor.visitor = this;
+
+ return processBuffer(indexBufferInfo, executor);
+
+ } else { // Non Indexed
+
+ // Check into which type the buffer needs to be casted
+ VertexExecutor executor;
+ executor.primitiveType = renderer->primitiveType();
+ executor.visitor = this;
+
+ return processBuffer(vertexBufferInfo, executor);
+ }
+ }
+ }
+ }
+}
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/trianglesvisitor_p.h b/src/render/backend/trianglesvisitor_p.h
new file mode 100644
index 000000000..b2ee8dd36
--- /dev/null
+++ b/src/render/backend/trianglesvisitor_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Paul Lemire paul.lemire350@gmail.com
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_TRIANGLESVISITOR_P_H
+#define QT3DRENDER_RENDER_TRIANGLESVISITOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qnodeid.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QEntity;
+}
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class GeometryRenderer;
+class NodeManagers;
+
+class Q_AUTOTEST_EXPORT TrianglesVisitor
+{
+public:
+ explicit TrianglesVisitor(NodeManagers *manager) : m_manager(manager) { }
+ virtual ~TrianglesVisitor();
+
+ void apply(const Qt3DCore::QEntity *entity);
+ void apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id);
+
+ virtual void visit(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b,
+ uint cndx, const QVector3D &c) = 0;
+
+protected:
+ NodeManagers *m_manager;
+ Qt3DCore::QNodeId m_nodeId;
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_RENDER_TRIANGLESVISITOR_P_H
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index bd14694cd..71ca42b80 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -371,19 +371,10 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
const QVector<QAspectJobPtr> geometryJobs = createGeometryRendererJobs();
jobs.append(geometryJobs);
-
- const QVector<QNodeId> geometryRendererTriangleUpdates = manager->geometryRendererManager()->geometryRenderersRequiringTriangleDataRefresh();
- Q_FOREACH (const QNodeId geomRendererId, geometryRendererTriangleUpdates) {
- Render::CalcGeometryTriangleVolumesPtr triangleComputeJob(new Render::CalcGeometryTriangleVolumes(geomRendererId, manager));
- triangleComputeJob->addDependency(d->m_framePreparationJob);
- pickBoundingVolumeJob->addDependency(triangleComputeJob);
- jobs.append(triangleComputeJob);
- }
-
// Only add dependency if not already present
const QVector<QWeakPointer<QAspectJob> > dependencies = pickBoundingVolumeJob->dependencies();
- if (std::find(dependencies.begin(), dependencies.end(), d->m_updateBoundingVolumeJob) == dependencies.end())
- pickBoundingVolumeJob->addDependency(d->m_updateBoundingVolumeJob);
+ if (std::find(dependencies.begin(), dependencies.end(), d->m_framePreparationJob) == dependencies.end())
+ pickBoundingVolumeJob->addDependency(d->m_framePreparationJob);
// Add all jobs to queue
jobs.append(d->m_calculateBoundingVolumeJob);
diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp
index feeb7c422..ccffe2c84 100644
--- a/src/render/jobs/calcboundingvolumejob.cpp
+++ b/src/render/jobs/calcboundingvolumejob.cpp
@@ -123,9 +123,11 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node)
const int stride = pickVolumeAttribute->byteStride() ? pickVolumeAttribute->byteStride() : sizeof(float) * pickVolumeAttribute->dataSize();
QVector<QVector3D> vertices(pickVolumeAttribute->count());
+ // TODO avoid copying the vertices
for (int c = 0, vC = vertices.size(); c < vC; ++c) {
QVector3D v;
const float *fptr = reinterpret_cast<const float*>(rawBuffer);
+ // TODO unwrap loop (switch?)
for (uint i = 0, m = qMin(pickVolumeAttribute->dataSize(), 3U); i < m; ++i)
v[i] = fptr[i];
vertices[c] = v;
diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp
index c592b348f..383127c27 100644
--- a/src/render/jobs/pickboundingvolumejob.cpp
+++ b/src/render/jobs/pickboundingvolumejob.cpp
@@ -47,7 +47,7 @@
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/sphere_p.h>
#include <Qt3DRender/private/geometryrenderer_p.h>
-#include <Qt3DRender/private/trianglesextractor_p.h>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
#include <Qt3DRender/private/triangleboundingvolume_p.h>
#include <Qt3DRender/private/qraycastingservice_p.h>
#include <Qt3DRender/qgeometryrenderer.h>
@@ -124,89 +124,159 @@ public:
};
-QVector<QBoundingVolume *> gatherBoundingVolumes(Entity *entity)
+QVector<Entity *> gatherEntities(Entity *entity)
{
- QVector<QBoundingVolume *> volumes;
+ QVector<Entity *> entities;
if (entity != Q_NULLPTR) {
- volumes.push_back(entity->worldBoundingVolume());
+ entities.push_back(entity);
// Traverse children
Q_FOREACH (Entity *child, entity->children())
- volumes += gatherBoundingVolumes(child);
+ entities += gatherEntities(child);
}
- return volumes;
+ return entities;
}
-class SphereBoundingVolumesGatherer : public QBoundingVolumeProvider
+class EntityGatherer
{
public:
- explicit SphereBoundingVolumesGatherer(Entity *root)
- : QBoundingVolumeProvider()
- , m_root(root)
+ explicit EntityGatherer(Entity *root)
+ : m_root(root)
, m_needsRefresh(true)
{
}
- QVector<QBoundingVolume *> boundingVolumes() const Q_DECL_FINAL
+ QVector<Entity *> entities() const
{
if (m_needsRefresh) {
- m_volumes = gatherBoundingVolumes(m_root);
+ m_entities = gatherEntities(m_root);
m_needsRefresh = false;
}
- return m_volumes;
+ return m_entities;
}
private:
Entity *m_root;
- mutable QVector<QBoundingVolume *> m_volumes;
+ mutable QVector<Entity *> m_entities;
mutable bool m_needsRefresh;
};
-
-class TriangleVolumeGatherer : public QBoundingVolumeProvider
+class CollisionVisitor : public TrianglesVisitor
{
public:
- explicit TriangleVolumeGatherer(Entity *root, NodeManagers *manager)
- : QBoundingVolumeProvider()
- , m_root(root)
- , m_manager(manager)
+ typedef QVector<QCollisionQueryResult::Hit> HitList;
+ HitList hits;
+
+ CollisionVisitor(NodeManagers* manager, const Entity *root, const Qt3DCore::QRay3D& ray) : TrianglesVisitor(manager), m_root(root), m_ray(ray), m_triangleIndex(0) { }
+private:
+ const Entity *m_root;
+ Qt3DCore::QRay3D m_ray;
+ Qt3DRender::QRayCastingService rayCasting;
+ uint m_triangleIndex;
+
+ void visit(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b,
+ uint cndx, const QVector3D &c)
{
- m_volumes = buildTriangleBoundingVolumes();
+ TriangleBoundingVolume volume(m_root->peerUuid(), a, b, c);
+ volume = volume.transform(*m_root->worldTransform());
+
+ QCollisionQueryResult::Hit queryResult = rayCasting.query(m_ray, &volume);
+ if (queryResult.m_distance > 0.) {
+ queryResult.m_triangleIndex = m_triangleIndex;
+ queryResult.m_vertexIndex[0] = andx;
+ queryResult.m_vertexIndex[1] = bndx;
+ queryResult.m_vertexIndex[2] = cndx;
+ hits.push_back(queryResult);
+ }
+
+ m_triangleIndex++;
}
+};
+
+struct CollisionGathererFunctor
+{
+ CollisionGathererFunctor() : m_renderer(0) { }
+ Renderer *m_renderer;
+ Qt3DCore::QRay3D m_ray;
+
+ typedef CollisionVisitor::HitList result_type;
- ~TriangleVolumeGatherer()
+ result_type operator ()(const Entity *entity) const
{
- qDeleteAll(m_volumes);
+ result_type result;
+
+ HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
+
+ // If the Entity which actually received the hit doesn't have
+ // an object picker component, we need to check the parent if it has one ...
+ while (objectPickerHandle.isNull() && entity != Q_NULLPTR) {
+ entity = entity->parent();
+ if (entity != Q_NULLPTR)
+ objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
+ }
+
+ ObjectPicker *objectPicker = m_renderer->nodeManagers()->objectPickerManager()->data(objectPickerHandle);
+ if (objectPicker == Q_NULLPTR)
+ return result; // don't bother picking entities that don't have an object picker
+
+ GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>();
+ if (!gRenderer)
+ return result;
+
+ Qt3DRender::QRayCastingService rayCasting;
+
+ if (rayHitsEntity(&rayCasting, entity)) {
+ CollisionVisitor visitor(m_renderer->nodeManagers(), entity, m_ray);
+ visitor.apply(gRenderer, entity->peerUuid());
+ result = visitor.hits;
+
+ struct
+ {
+ bool operator()(const result_type::value_type &a, const result_type::value_type &b)
+ {
+ return a.m_distance < b.m_distance;
+ }
+ } compareHitsDistance;
+ std::sort(result.begin(), result.end(), compareHitsDistance);
+ }
+
+ return result;
}
- QVector<QBoundingVolume *> boundingVolumes() const Q_DECL_FINAL
+ bool rayHitsEntity(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const
{
- return m_volumes;
+ const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume());
+ return queryResult.m_distance >= 0.f;
}
+};
-private:
- QVector<QBoundingVolume *> buildTriangleBoundingVolumes()
- {
- QVector<QBoundingVolume *> volumes;
- if (m_root) {
- GeometryRenderer *gRenderer = m_root->renderComponent<GeometryRenderer>();
- if (gRenderer) {
- const QVector<QBoundingVolume *> localVolumes = gRenderer->triangleData();
- volumes.reserve(localVolumes.size());
- Q_FOREACH (const QBoundingVolume *v, localVolumes) {
- TriangleBoundingVolume *worldVolume = new TriangleBoundingVolume();
- *worldVolume = static_cast<const TriangleBoundingVolume *>(v)->transformed(*m_root->worldTransform());
- volumes.push_back(worldVolume);
- }
+CollisionVisitor::HitList reduceToFirstHit(CollisionVisitor::HitList &result, const CollisionVisitor::HitList &intermediate)
+{
+ if (!intermediate.empty()) {
+ if (result.empty())
+ result.push_back(intermediate.front());
+ float closest = result.front().m_distance;
+ Q_FOREACH (const CollisionVisitor::HitList::value_type& v, intermediate) {
+ if (v.m_distance < closest) {
+ result.push_front(v);
+ closest = v.m_distance;
}
}
- return volumes;
+
+ while (result.size() > 1)
+ result.pop_back();
}
+ return result;
+}
- Entity *m_root;
- NodeManagers *m_manager;
- QVector<QBoundingVolume *> m_volumes;
-};
+// Unordered
+CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate)
+{
+ if (!intermediate.empty())
+ results << intermediate;
+ return results;
+}
} // anonymous
@@ -240,146 +310,125 @@ void PickBoundingVolumeJob::run()
if (m_mouseEvents.empty())
return;
- Qt3DCore::QServiceLocator *services = m_renderer->services();
- QAbstractCollisionQueryService *rayCasting = services->service<QAbstractCollisionQueryService>
- (Qt3DCore::QServiceLocator::CollisionService);
+ ViewportCameraGatherer vcGatherer;
+ const QVector<ViewportCameraPair> vcPairs = vcGatherer.gather(m_renderer->frameGraphRoot());
- if (rayCasting == Q_NULLPTR) {
- Qt3DRender::QRayCastingService *rayCastingService = new QRayCastingService();
- services->registerServiceProvider(Qt3DCore::QServiceLocator::CollisionService, rayCastingService);
- rayCasting = rayCastingService;
- }
+ EntityGatherer entitiesGatherer(m_node);
- if (rayCasting != Q_NULLPTR) {
- ViewportCameraGatherer vcGatherer;
- const QVector<ViewportCameraPair> vcPairs = vcGatherer.gather(m_renderer->frameGraphRoot());
-
- SphereBoundingVolumesGatherer sphereGatherer(m_node);
-
- if (!vcPairs.empty()) {
- Q_FOREACH (const QMouseEvent &event, m_mouseEvents) {
- m_hoveredPickersToClear = m_hoveredPickers;
- ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
- Q_FOREACH (const ViewportCameraPair &vc, vcPairs) {
- QVector<QCollisionQueryResult::Hit> sphereHits = sphereHitsForViewportAndCamera(event.pos(),
- vc.viewport,
- vc.cameraId,
- rayCasting,
- &sphereGatherer);
-#if 0
- Q_FOREACH (const Qt3DCore::QCollisionQueryResult::Hit sphereHit, sphereHits) {
- if (triangleHitsForViewportAndCamera(event.pos(),
- vc.viewport,
- vc.cameraId,
- sphereHit.m_entityId,
- rayCasting).isEmpty())
- sphereHits.removeAll(sphereHit);
- }
-#endif
+ if (!vcPairs.empty()) {
+ Q_FOREACH (const QMouseEvent &event, m_mouseEvents) {
+ m_hoveredPickersToClear = m_hoveredPickers;
+ ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
- // If we have hits
- if (!sphereHits.isEmpty()) {
- // Note: how can we control that we want the first/last/all elements along the ray to be picked
+ Q_FOREACH (const ViewportCameraPair &vc, vcPairs) {
+ typedef CollisionGathererFunctor::result_type HitList;
+ CollisionGathererFunctor gathererFunctor;
+ gathererFunctor.m_renderer = m_renderer;
+ gathererFunctor.m_ray = rayForViewportAndCamera(event.pos(), vc.viewport, vc.cameraId);
+ HitList sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reduceToAllHits);
- // How do we differentiate betwnee an Entity with no GeometryRenderer and one with one, both having
- // an ObjectPicker component when it comes
+ // If we have hits
+ if (!sphereHits.isEmpty()) {
+ // Note: how can we control that we want the first/last/all elements along the ray to be picked
- // We want to gather hits against triangles
- // build a triangle based bounding volume
+ // How do we differentiate betwnee an Entity with no GeometryRenderer and one with one, both having
+ // an ObjectPicker component when it comes
- Q_FOREACH (const QCollisionQueryResult::Hit &hit, sphereHits) {
- Entity *entity = m_manager->renderNodesManager()->lookupResource(hit.m_entityId);
- HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
+ // We want to gather hits against triangles
+ // build a triangle based bounding volume
- // If the Entity which actually received the hit doesn't have
- // an object picker component, we need to check the parent if it has one ...
- while (objectPickerHandle.isNull() && entity != Q_NULLPTR) {
- entity = entity->parent();
- if (entity != Q_NULLPTR)
- objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
- }
+ Q_FOREACH (const QCollisionQueryResult::Hit &hit, sphereHits) {
+ Entity *entity = m_manager->renderNodesManager()->lookupResource(hit.m_entityId);
+ HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
- ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle);
-
- if (objectPicker != Q_NULLPTR) {
- // Send the corresponding event
- QVector3D localIntersection = hit.m_intersection;
- if (entity && entity->worldTransform())
- localIntersection = hit.m_intersection * entity->worldTransform()->inverted();
- QPickEventPtr pickEvent(new QPickEvent(hit.m_intersection, localIntersection, hit.m_distance));
-
- switch (event.type()) {
- case QEvent::MouseButtonPress: {
- // Store pressed object handle
- m_currentPicker = objectPickerHandle;
- // Send pressed event to m_currentPicker
- objectPicker->onPressed(pickEvent);
- }
- break;
+ // If the Entity which actually received the hit doesn't have
+ // an object picker component, we need to check the parent if it has one ...
+ while (objectPickerHandle.isNull() && entity != Q_NULLPTR) {
+ entity = entity->parent();
+ if (entity != Q_NULLPTR)
+ objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
+ }
- case QEvent::MouseButtonRelease: {
- // Send release event to m_currentPicker
- if (lastCurrentPicker != Q_NULLPTR) {
- lastCurrentPicker->onClicked(pickEvent);
- lastCurrentPicker->onReleased(pickEvent);
- }
- break;
- }
+ ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle);
+
+ if (objectPicker != Q_NULLPTR) {
+ // Send the corresponding event
+ QVector3D localIntersection = hit.m_intersection;
+ if (entity && entity->worldTransform())
+ localIntersection = hit.m_intersection * entity->worldTransform()->inverted();
+ QPickEventPtr pickEvent(new QPickEvent(hit.m_intersection, localIntersection, hit.m_distance,
+ hit.m_triangleIndex, hit.m_vertexIndex[0], hit.m_vertexIndex[1], hit.m_vertexIndex[2]));
+
+ switch (event.type()) {
+ case QEvent::MouseButtonPress: {
+ // Store pressed object handle
+ m_currentPicker = objectPickerHandle;
+ // Send pressed event to m_currentPicker
+ objectPicker->onPressed(pickEvent);
+ }
+ break;
- case Qt::TapGesture: {
- objectPicker->onClicked(pickEvent);
- break;
+ case QEvent::MouseButtonRelease: {
+ // Send release event to m_currentPicker
+ if (lastCurrentPicker != Q_NULLPTR) {
+ lastCurrentPicker->onClicked(pickEvent);
+ lastCurrentPicker->onReleased(pickEvent);
}
+ break;
+ }
- case QEvent::HoverMove:
- case QEvent::MouseMove: {
- if (!m_hoveredPickers.contains(objectPickerHandle)) {
- if (objectPicker->hoverEnabled()) {
- // Send entered event to objectPicker
- objectPicker->onEntered();
- // and save it in the hoveredPickers
- m_hoveredPickers.push_back(objectPickerHandle);
- }
+ case Qt::TapGesture: {
+ objectPicker->onClicked(pickEvent);
+ break;
+ }
+
+ case QEvent::HoverMove:
+ case QEvent::MouseMove: {
+ if (!m_hoveredPickers.contains(objectPickerHandle)) {
+ if (objectPicker->hoverEnabled()) {
+ // Send entered event to objectPicker
+ objectPicker->onEntered();
+ // and save it in the hoveredPickers
+ m_hoveredPickers.push_back(objectPickerHandle);
}
- break;
}
+ break;
+ }
- default:
- break;
- }
+ default:
+ break;
}
+ }
- // The ObjectPicker was hit -> it is still being hovered
- m_hoveredPickersToClear.removeAll(objectPickerHandle);
+ // The ObjectPicker was hit -> it is still being hovered
+ m_hoveredPickersToClear.removeAll(objectPickerHandle);
- lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
- }
+ lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
+ }
- // Otherwise no hits
- } else {
- switch (event.type()) {
- case QEvent::MouseButtonRelease: {
- // Send release event to m_currentPicker
- if (lastCurrentPicker != Q_NULLPTR) {
- QPickEventPtr pickEvent(new QPickEvent);
- lastCurrentPicker->onReleased(pickEvent);
- }
- break;
- }
- default:
- break;
+ // Otherwise no hits
+ } else {
+ switch (event.type()) {
+ case QEvent::MouseButtonRelease: {
+ // Send release event to m_currentPicker
+ if (lastCurrentPicker != Q_NULLPTR) {
+ QPickEventPtr pickEvent(new QPickEvent);
+ lastCurrentPicker->onReleased(pickEvent);
}
+ break;
+ }
+ default:
+ break;
}
}
}
-
- // Clear Hovered elements that needs to be cleared
- // Send exit event to object pickers on which we
- // had set the hovered flag for a previous frame
- // and that aren't being hovered any longer
- clearPreviouslyHoveredPickers();
-
}
+
+ // Clear Hovered elements that needs to be cleared
+ // Send exit event to object pickers on which we
+ // had set the hovered flag for a previous frame
+ // and that aren't being hovered any longer
+ clearPreviouslyHoveredPickers();
}
// Clear mouse events so that they aren't processed again for the next frame
@@ -402,70 +451,36 @@ void PickBoundingVolumeJob::viewMatrixForCamera(const Qt3DCore::QNodeId &cameraI
QRect PickBoundingVolumeJob::windowViewport(const QRectF &relativeViewport) const
{
- // // TO DO: find another way to retrieve the size since this won't work with Scene3D
- // const QSurface *s = m_renderer->surface();
- // if (s) {
- // const int surfaceWidth = s->size().width();
- // const int surfaceHeight = s->size().height();
- // return QRect(relativeViewport.x() * surfaceWidth,
- // (1.0 - relativeViewport.y() - relativeViewport.height()) * surfaceHeight,
- // relativeViewport.width() * surfaceWidth,
- // relativeViewport.height() * surfaceHeight);
- // }
- // return relativeViewport.toRect();
- return QRect();
-}
-
-
-QVector<QCollisionQueryResult::Hit> PickBoundingVolumeJob::sphereHitsForViewportAndCamera(const QPoint &pos,
- const QRectF &relativeViewport,
- const Qt3DCore::QNodeId &cameraId,
- QAbstractCollisionQueryService *rayCasting,
- QBoundingVolumeProvider *volumeProvider) const
-{
- QMatrix4x4 viewMatrix;
- QMatrix4x4 projectionMatrix;
- viewMatrixForCamera(cameraId, viewMatrix, projectionMatrix);
- const QRect viewport = windowViewport(relativeViewport);
-
- // const QSurface *s = m_renderer->surface();
// TO DO: find another way to retrieve the size since this won't work with Scene3D
- // In GL the y is inverted compared to Qt
- // const QPoint glCorrectPos = s ? QPoint(pos.x(), s->size().height() - pos.y()) : pos;
- const QPoint glCorrectPos = pos;
- const Qt3DCore::QRay3D ray = intersectionRay(glCorrectPos, viewMatrix, projectionMatrix, viewport);
- const QQueryHandle rayCastingHandle = rayCasting->query(ray, QAbstractCollisionQueryService::AllHits, volumeProvider);
- const QCollisionQueryResult queryResult = rayCasting->fetchResult(rayCastingHandle);
- return queryResult.hits();
+ // const QSize s = m_renderer->surfaceSize();
+ // if (s.isValid()) {
+ // const int surfaceWidth = s.width();
+ // const int surfaceHeight = s.height();
+ // return QRect(relativeViewport.x() * surfaceWidth,
+ // (1.0 - relativeViewport.y() - relativeViewport.height()) * surfaceHeight,
+ // relativeViewport.width() * surfaceWidth,
+ // relativeViewport.height() * surfaceHeight);
+ // }
+ // return relativeViewport.toRect();
+ return QRect();
}
-QVector<QCollisionQueryResult::Hit> PickBoundingVolumeJob::triangleHitsForViewportAndCamera(const QPoint &pos,
- const QRectF &relativeViewport,
- const Qt3DCore::QNodeId &cameraId,
- const Qt3DCore::QNodeId &entityId,
- QAbstractCollisionQueryService *rayCasting) const
+Qt3DCore::QRay3D PickBoundingVolumeJob::rayForViewportAndCamera(const QPoint &pos,
+ const QRectF &relativeViewport,
+ const Qt3DCore::QNodeId &cameraId) const
{
QMatrix4x4 viewMatrix;
QMatrix4x4 projectionMatrix;
viewMatrixForCamera(cameraId, viewMatrix, projectionMatrix);
const QRect viewport = windowViewport(relativeViewport);
- // const QSurface *s = m_renderer->surface();
// TO DO: find another way to retrieve the size since this won't work with Scene3D
- // In GL the y is inverted compared to Qt
- // const QPoint glCorrectPos = s ? QPoint(pos.x(), s->size().height() - pos.y()) : pos;
+ // const QSize s = m_renderer->surfaceSize();
+ // // In GL the y is inverted compared to Qt
+ // const QPoint glCorrectPos = s.isValid() ? QPoint(pos.x(), s.height() - pos.y()) : pos;
const QPoint glCorrectPos = pos;
const Qt3DCore::QRay3D ray = intersectionRay(glCorrectPos, viewMatrix, projectionMatrix, viewport);
-
- // Note: improve this further to only compute this once and not every time
- TriangleVolumeGatherer boundingVolumeProvider(m_manager->lookupResource<Entity, EntityManager>(entityId),
- m_manager);
-
- const QQueryHandle rayCastingHandle = rayCasting->query(ray,
- QAbstractCollisionQueryService::AllHits,
- &boundingVolumeProvider);
- const QCollisionQueryResult queryResult = rayCasting->fetchResult(rayCastingHandle);
- return queryResult.hits();
+ return ray;
}
void PickBoundingVolumeJob::clearPreviouslyHoveredPickers()
@@ -484,4 +499,3 @@ void PickBoundingVolumeJob::clearPreviouslyHoveredPickers()
} // namespace Qt3DRender
QT_END_NAMESPACE
-
diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h
index 37f5bcc41..459b88e9e 100644
--- a/src/render/jobs/pickboundingvolumejob_p.h
+++ b/src/render/jobs/pickboundingvolumejob_p.h
@@ -96,16 +96,9 @@ private:
QMatrix4x4 &viewMatrix,
QMatrix4x4 &projectionMatrix) const;
QRect windowViewport(const QRectF &relativeViewport) const;
- QVector<QCollisionQueryResult::Hit> sphereHitsForViewportAndCamera(const QPoint &pos,
- const QRectF &relativeViewport,
- const Qt3DCore::QNodeId &cameraId,
- QAbstractCollisionQueryService *rayCasting,
- QBoundingVolumeProvider *volumeProvider) const;
- QVector<QCollisionQueryResult::Hit> triangleHitsForViewportAndCamera(const QPoint &pos,
- const QRectF &relativeViewport,
- const Qt3DCore::QNodeId &cameraId,
- const Qt3DCore::QNodeId &entityId,
- QAbstractCollisionQueryService *rayCasting) const;
+ Qt3DCore::QRay3D rayForViewportAndCamera(const QPoint &pos,
+ const QRectF &relativeViewport,
+ const Qt3DCore::QNodeId &cameraId) const;
void clearPreviouslyHoveredPickers();
HObjectPicker m_currentPicker;
QVector<HObjectPicker> m_hoveredPickers;
diff --git a/src/render/picking/qpickevent.cpp b/src/render/picking/qpickevent.cpp
index 420bab16f..a8f15dd08 100644
--- a/src/render/picking/qpickevent.cpp
+++ b/src/render/picking/qpickevent.cpp
@@ -55,6 +55,10 @@ public:
QVector3D m_worldIntersection;
QVector3D m_localIntersection;
float m_distance;
+ uint m_triangleIndex;
+ uint m_vertex1Index;
+ uint m_vertex2Index;
+ uint m_vertex3Index;
};
QPickEvent::QPickEvent()
@@ -62,13 +66,18 @@ QPickEvent::QPickEvent()
{
}
-QPickEvent::QPickEvent(const QVector3D &intersection, const QVector3D &localIntersection, float distance)
+QPickEvent::QPickEvent(const QVector3D &intersection, const QVector3D &localIntersection, float distance,
+ uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index)
: QObject(*new QPickEventPrivate())
{
Q_D(QPickEvent);
d->m_distance = distance;
d->m_worldIntersection = intersection;
d->m_localIntersection = localIntersection;
+ d->m_triangleIndex = triangleIndex;
+ d->m_vertex1Index = vertex1Index;
+ d->m_vertex2Index = vertex2Index;
+ d->m_vertex3Index = vertex3Index;
}
QPickEvent::~QPickEvent()
@@ -108,6 +117,30 @@ const QVector3D &QPickEvent::localIntersection() const
return d->m_localIntersection;
}
+uint QPickEvent::triangleIndex() const
+{
+ Q_D(const QPickEvent);
+ return d->m_triangleIndex;
+}
+
+uint QPickEvent::vertex1Index() const
+{
+ Q_D(const QPickEvent);
+ return d->m_vertex1Index;
+}
+
+uint QPickEvent::vertex2Index() const
+{
+ Q_D(const QPickEvent);
+ return d->m_vertex2Index;
+}
+
+uint QPickEvent::vertex3Index() const
+{
+ Q_D(const QPickEvent);
+ return d->m_vertex3Index;
+}
+
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/picking/qpickevent.h b/src/render/picking/qpickevent.h
index 4734a912d..4c705ffc6 100644
--- a/src/render/picking/qpickevent.h
+++ b/src/render/picking/qpickevent.h
@@ -57,9 +57,14 @@ class QT3DRENDERSHARED_EXPORT QPickEvent : public QObject
Q_PROPERTY(float distance READ distance CONSTANT)
Q_PROPERTY(QVector3D localIntersection READ localIntersection CONSTANT)
Q_PROPERTY(QVector3D worldIntersection READ worldIntersection CONSTANT)
+ Q_PROPERTY(uint triangleIndex READ triangleIndex CONSTANT)
+ Q_PROPERTY(uint vertex1Index READ vertex1Index CONSTANT)
+ Q_PROPERTY(uint vertex2Index READ vertex2Index CONSTANT)
+ Q_PROPERTY(uint vertex3Index READ vertex3Index CONSTANT)
public:
QPickEvent();
- QPickEvent(const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance);
+ QPickEvent(const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance,
+ uint triangleIndex = 0, uint vertex1Index = 0, uint vertex2Index = 0, uint vertex3Index = 0);
~QPickEvent();
bool isAccepted() const;
@@ -70,6 +75,10 @@ public Q_SLOTS:
float distance() const;
const QVector3D &worldIntersection() const;
const QVector3D &localIntersection() const;
+ uint triangleIndex() const;
+ uint vertex1Index() const;
+ uint vertex2Index() const;
+ uint vertex3Index() const;
Q_SIGNALS:
void acceptedChanged(bool accepted);
diff --git a/src/render/raycasting/qabstractcollisionqueryservice_p.h b/src/render/raycasting/qabstractcollisionqueryservice_p.h
index 051946d5e..524a6d9f9 100644
--- a/src/render/raycasting/qabstractcollisionqueryservice_p.h
+++ b/src/render/raycasting/qabstractcollisionqueryservice_p.h
@@ -62,8 +62,10 @@ namespace Qt3DCore {
class QRay3D;
}
+class QAbstractCollisionQueryServicePrivate;
namespace Qt3DRender {
+class QBoundingVolume;
class QBoundingVolumeProvider;
class QAbstractCollisionQueryServicePrivate : public Qt3DCore::QAbstractServiceProviderPrivate
@@ -83,6 +85,7 @@ public:
};
virtual QQueryHandle query(const Qt3DCore::QRay3D &ray, QueryMode mode, QBoundingVolumeProvider *provider) = 0;
+ virtual QCollisionQueryResult::Hit query(const Qt3DCore::QRay3D &ray, const QBoundingVolume* volume) = 0;
virtual QCollisionQueryResult fetchResult(const QQueryHandle &handle) = 0;
virtual QVector<QCollisionQueryResult> fetchAllResults() const = 0;
diff --git a/src/render/raycasting/qcollisionqueryresult_p.h b/src/render/raycasting/qcollisionqueryresult_p.h
index 21035e6a8..ca3f5b286 100644
--- a/src/render/raycasting/qcollisionqueryresult_p.h
+++ b/src/render/raycasting/qcollisionqueryresult_p.h
@@ -70,6 +70,8 @@ public:
Qt3DCore::QNodeId m_entityId;
QVector3D m_intersection;
float m_distance;
+ uint m_triangleIndex;
+ uint m_vertexIndex[3];
};
QCollisionQueryResult();
diff --git a/src/render/raycasting/qraycastingservice.cpp b/src/render/raycasting/qraycastingservice.cpp
index 0b183f087..f584e5f74 100644
--- a/src/render/raycasting/qraycastingservice.cpp
+++ b/src/render/raycasting/qraycastingservice.cpp
@@ -141,6 +141,19 @@ QCollisionQueryResult QRayCastingServicePrivate::collides(const Qt3DCore::QRay3D
return result;
}
+QCollisionQueryResult::Hit QRayCastingServicePrivate::collides(const Qt3DCore::QRay3D &ray, const Qt3DRender::QBoundingVolume *volume)
+{
+ QCollisionQueryResult::Hit result;
+ Hit hit = volumeRayIntersection(volume, ray);
+ if (hit.intersects)
+ {
+ result.m_distance = hit.distance;
+ result.m_entityId = hit.id;
+ result.m_intersection = hit.intersection;
+ }
+ return result;
+}
+
QRayCastingServicePrivate::QRayCastingServicePrivate(const QString &description)
: QAbstractCollisionQueryServicePrivate(description)
, m_handlesCount(0)
@@ -170,6 +183,13 @@ QQueryHandle QRayCastingService::query(const Qt3DCore::QRay3D &ray,
return handle;
}
+QCollisionQueryResult::Hit QRayCastingService::query(const Qt3DCore::QRay3D &ray, const QBoundingVolume *volume)
+{
+ Q_D(QRayCastingService);
+
+ return d->collides(ray, volume);
+}
+
QCollisionQueryResult QRayCastingService::fetchResult(const QQueryHandle &handle)
{
Q_D(QRayCastingService);
diff --git a/src/render/raycasting/qraycastingservice_p.h b/src/render/raycasting/qraycastingservice_p.h
index b4fdc1549..66c24fb8d 100644
--- a/src/render/raycasting/qraycastingservice_p.h
+++ b/src/render/raycasting/qraycastingservice_p.h
@@ -60,7 +60,6 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QBoundingVolume;
class QBoundingVolumeProvider;
class QRayCastingServicePrivate;
@@ -72,6 +71,7 @@ public:
QRayCastingService();
QQueryHandle query(const Qt3DCore::QRay3D &ray, QueryMode mode, QBoundingVolumeProvider *provider) Q_DECL_OVERRIDE;
+ QCollisionQueryResult::Hit query(const Qt3DCore::QRay3D &ray, const QBoundingVolume *volume) Q_DECL_OVERRIDE;
QCollisionQueryResult fetchResult(const QQueryHandle &handle) Q_DECL_OVERRIDE;
QVector<QCollisionQueryResult> fetchAllResults() const Q_DECL_OVERRIDE;
@@ -93,6 +93,8 @@ public:
QBoundingVolumeProvider *provider,
QAbstractCollisionQueryService::QueryMode mode,
const QQueryHandle &handle);
+ QCollisionQueryResult::Hit collides(const Qt3DCore::QRay3D &ray,
+ const QBoundingVolume *volume);
Q_DECLARE_PUBLIC(QRayCastingService)