From 28ec1ca1883e0fe9b8b0e0de4049564ae652bd90 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Thu, 10 Dec 2015 15:58:05 +0000 Subject: Refactor picking to use one thread per entity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/render/backend/render-backend.pri | 2 + src/render/backend/trianglesextractor.cpp | 447 +------------------------- src/render/backend/trianglesextractor_p.h | 13 +- src/render/backend/trianglesvisitor.cpp | 518 ++++++++++++++++++++++++++++++ src/render/backend/trianglesvisitor_p.h | 91 ++++++ 5 files changed, 630 insertions(+), 441 deletions(-) create mode 100644 src/render/backend/trianglesvisitor.cpp create mode 100644 src/render/backend/trianglesvisitor_p.h (limited to 'src/render/backend') 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 #include #include #include #include #include +#include #include #include #include @@ -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 -QVector traverseTrianglesIndexed(index *indices, - vertex *vertices, - const BufferInfo &indexInfo, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector 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 -QVector traverseTriangles(vertex *vertices, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector 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 -QVector traverseTriangleStripIndexed(index *indices, - vertex *vertices, - const BufferInfo &indexInfo, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector 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 -QVector traverseTriangleStrip(vertex *vertices, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector 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 -QVector traverseTriangleFanIndexed(index *indices, - vertex *vertices, - const BufferInfo &indexInfo, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector 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(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 -QVector traverseTriangleFan(vertex *vertices, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector 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 -QVector traverseTriangleAdjacencyIndexed(index *indices, - vertex *vertices, - const BufferInfo &indexInfo, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector 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 -QVector traverseTriangleAdjacency(vertex *vertices, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector 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 struct EnumToType; -template <> struct EnumToType { typedef const char type; }; -template <> struct EnumToType { typedef const uchar type; }; -template <> struct EnumToType { typedef const short type; }; -template <> struct EnumToType { typedef const ushort type; }; -template <> struct EnumToType { typedef const int type; }; -template <> struct EnumToType { typedef const uint type; }; -template <> struct EnumToType { typedef const float type; }; -template <> struct EnumToType { typedef const double type; }; - -template -typename EnumToType::type *castToType(const QByteArray &u, uint byteOffset) -{ - return reinterpret_cast< typename EnumToType::type *>(u.constData() + byteOffset); -} - -template -QVector processBuffer(const BufferInfo &info, Func &f) -{ - switch (info.type) { - case QAttribute::Byte: return f(info, castToType(info.data, info.byteOffset)); - case QAttribute::UnsignedByte: return f(info, castToType(info.data, info.byteOffset)); - case QAttribute::Short: return f(info, castToType(info.data, info.byteOffset)); - case QAttribute::UnsignedShort: return f(info, castToType(info.data, info.byteOffset)); - case QAttribute::Int: return f(info, castToType(info.data, info.byteOffset)); - case QAttribute::UnsignedInt: return f(info, castToType(info.data, info.byteOffset)); - case QAttribute::Float: return f(info, castToType(info.data, info.byteOffset)); - case QAttribute::Double: return f(info, castToType(info.data, info.byteOffset)); - default: - return ReturnType(); - } -} - -template -struct IndexedVertexExecutor -{ - template - 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 -struct IndexExecutor -{ - BufferInfo vertexBufferInfo; - - template - ReturnType operator ()( const BufferInfo &indexInfo, Index *indices) - { - IndexedVertexExecutor exec; - exec.primitiveType = primitiveType; - exec.indices = indices; - exec.indexBufferInfo = indexInfo; - exec.id = id; - return processBuffer(vertexBufferInfo, exec); - } - - Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType; - Qt3DCore::QNodeId id; -}; - -template -struct VertexExecutor -{ - template - 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 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(m_renderer->geometryId()); - - if (geom) { - Qt3DRender::Render::Attribute *attribute = Q_NULLPTR; - Q_FOREACH (const Qt3DCore::QNodeId attrId, geom->attributes()) { - attribute = m_manager->lookupResource(attrId); - if (attribute){ - if (attribute->name() == QAttribute::defaultPositionAttributeName()) - positionAttribute = attribute; - else if (attribute->attributeType() == QAttribute::IndexAttribute) - indexAttribute = attribute; - } - } - - if (positionAttribute) - positionBuffer = m_manager->lookupResource(positionAttribute->bufferId()); - if (indexAttribute) - indexBuffer = m_manager->lookupResource(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 = m_renderer->primitiveType(); - executor.id = id; - - return processBuffer >(indexBufferInfo, executor); - - } else { // Non Indexed - - // Check into which type the buffer needs to be casted - VertexExecutor > executor; - executor.primitiveType = m_renderer->primitiveType(); - executor.id = id; + qDeleteAll(m_volumes); + apply(m_renderer, id); + return m_volumes; +} - return processBuffer >(vertexBufferInfo, executor); - } - } - } - } - return QVector(); +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 +#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 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +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 +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 +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 +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 +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(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 +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 +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 +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 struct EnumToType; +template <> struct EnumToType { typedef const char type; }; +template <> struct EnumToType { typedef const uchar type; }; +template <> struct EnumToType { typedef const short type; }; +template <> struct EnumToType { typedef const ushort type; }; +template <> struct EnumToType { typedef const int type; }; +template <> struct EnumToType { typedef const uint type; }; +template <> struct EnumToType { typedef const float type; }; +template <> struct EnumToType { typedef const double type; }; + +template +typename EnumToType::type *castToType(const QByteArray &u, uint byteOffset) +{ + return reinterpret_cast< typename EnumToType::type *>(u.constData() + byteOffset); +} + +template +void processBuffer(const BufferInfo &info, Func &f) +{ + switch (info.type) { + case QAttribute::Byte: f(info, castToType(info.data, info.byteOffset)); + return; + case QAttribute::UnsignedByte: f(info, castToType(info.data, info.byteOffset)); + return; + case QAttribute::Short: f(info, castToType(info.data, info.byteOffset)); + return; + case QAttribute::UnsignedShort: f(info, castToType(info.data, info.byteOffset)); + return; + case QAttribute::Int: f(info, castToType(info.data, info.byteOffset)); + return; + case QAttribute::UnsignedInt: f(info, castToType(info.data, info.byteOffset)); + return; + case QAttribute::Float: f(info, castToType(info.data, info.byteOffset)); + return; + case QAttribute::Double: f(info, castToType(info.data, info.byteOffset)); + return; + default: + return; + } +} + +template +struct IndexedVertexExecutor +{ + template + 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 + void operator ()( const BufferInfo &indexInfo, Index *indices) + { + IndexedVertexExecutor 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 + 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(renderer->geometryId()); + + if (geom) { + Qt3DRender::Render::Attribute *attribute = Q_NULLPTR; + Q_FOREACH (const Qt3DCore::QNodeId attrId, geom->attributes()) { + attribute = m_manager->lookupResource(attrId); + if (attribute){ + if (attribute->name() == QAttribute::defaultPositionAttributeName()) + positionAttribute = attribute; + else if (attribute->attributeType() == QAttribute::IndexAttribute) + indexAttribute = attribute; + } + } + + if (positionAttribute) + positionBuffer = m_manager->lookupResource(positionAttribute->bufferId()); + if (indexAttribute) + indexBuffer = m_manager->lookupResource(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 + +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 -- cgit v1.2.3