diff options
author | Mike Krus <mike.krus@kdab.com> | 2015-12-10 15:58:05 +0000 |
---|---|---|
committer | Mike Krus <mike.krus@kdab.com> | 2016-01-25 14:13:13 +0000 |
commit | 28ec1ca1883e0fe9b8b0e0de4049564ae652bd90 (patch) | |
tree | 3722809fc54b75d08b08fb68bd5d9d56fbe24342 /src/render/backend | |
parent | 4ad00b344bc79e34f2ba2f8355e65c7948791389 (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>
Diffstat (limited to 'src/render/backend')
-rw-r--r-- | src/render/backend/render-backend.pri | 2 | ||||
-rw-r--r-- | src/render/backend/trianglesextractor.cpp | 447 | ||||
-rw-r--r-- | src/render/backend/trianglesextractor_p.h | 13 | ||||
-rw-r--r-- | src/render/backend/trianglesvisitor.cpp | 518 | ||||
-rw-r--r-- | src/render/backend/trianglesvisitor_p.h | 91 |
5 files changed, 630 insertions, 441 deletions
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 |