diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2015-11-13 16:15:18 +0100 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2015-11-24 13:01:55 +0000 |
commit | 1b2c6c21705aed257555eb39c01ea236e741c637 (patch) | |
tree | 13ba2c9beda964769bda6e59adf30e48adaf89a5 /src/render/backend/trianglesextractor.cpp | |
parent | ae6e9f6b25a77064190de1f65358e3bb98e2a37b (diff) |
TriangleExtractor added
Will allow to retrive a vector of TriangleBoundingVolumes given a
GeometryRenderer/Geometry/Attributes and Buffers
Change-Id: Ieb1040b2c190ef2a8c03b92e2ecb8739832d7b43
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src/render/backend/trianglesextractor.cpp')
-rw-r--r-- | src/render/backend/trianglesextractor.cpp | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/src/render/backend/trianglesextractor.cpp b/src/render/backend/trianglesextractor.cpp new file mode 100644 index 000000000..098284c73 --- /dev/null +++ b/src/render/backend/trianglesextractor.cpp @@ -0,0 +1,502 @@ +/**************************************************************************** +** +** 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 "trianglesextractor_p.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/geometry_p.h> +#include <Qt3DRender/private/attribute_p.h> +#include <Qt3DRender/private/buffer_p.h> +#include <Qt3DRender/private/triangleboundingvolume_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> +QVector<Qt3DCore::QBoundingVolume *> traverseTrianglesIndexed(index *indices, + vertex *vertices, + const BufferInfo &indexInfo, + const BufferInfo &vertexInfo, + const Qt3DCore::QNodeId id) +{ + QVector<Qt3DCore::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[0], abc[1], abc[2])); + i += 3; + } + + return tris; +} + +// vertices are already offset +template<typename vertex> +QVector<Qt3DCore::QBoundingVolume *> traverseTriangles(vertex *vertices, + const BufferInfo &vertexInfo, + const Qt3DCore::QNodeId id) +{ + QVector<Qt3DCore::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[0], abc[1], abc[2])); + i += 3; + } + return tris; +} + +// indices, vertices are already offset +template<typename index, typename vertex> +QVector<Qt3DCore::QBoundingVolume *> traverseTriangleStripIndexed(index *indices, + vertex *vertices, + const BufferInfo &indexInfo, + const BufferInfo &vertexInfo, + const Qt3DCore::QNodeId id) +{ + QVector<Qt3DCore::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[0], abc[1], abc[2])); + ++i; + } + + return tris; +} + +// vertices are already offset +template<typename vertex> +QVector<Qt3DCore::QBoundingVolume *> traverseTriangleStrip(vertex *vertices, + const BufferInfo &vertexInfo, + const Qt3DCore::QNodeId id) +{ + QVector<Qt3DCore::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[0], abc[1], abc[2])); + ++i; + } + return tris; +} + +// indices, vertices are already offset +template<typename index, typename vertex> +QVector<Qt3DCore::QBoundingVolume *> traverseTriangleFanIndexed(index *indices, + vertex *vertices, + const BufferInfo &indexInfo, + const BufferInfo &vertexInfo, + const Qt3DCore::QNodeId id) +{ + QVector<Qt3DCore::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[0], abc[1], abc[2])); + i += 2; + } + + return tris; +} + +// vertices are already offset +template<typename vertex> +QVector<Qt3DCore::QBoundingVolume *> traverseTriangleFan(vertex *vertices, + const BufferInfo &vertexInfo, + const Qt3DCore::QNodeId id) +{ + QVector<Qt3DCore::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[0], abc[1], abc[2])); + i += 2; + } + return tris; +} + +// indices, vertices are already offset +template<typename index, typename vertex> +QVector<Qt3DCore::QBoundingVolume *> traverseTriangleAdjacencyIndexed(index *indices, + vertex *vertices, + const BufferInfo &indexInfo, + const BufferInfo &vertexInfo, + const Qt3DCore::QNodeId id) +{ + QVector<Qt3DCore::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[0], abc[1], abc[2])); + i += 6; + } + + return tris; +} + +// vertices are already offset +template<typename vertex> +QVector<Qt3DCore::QBoundingVolume *> traverseTriangleAdjacency(vertex *vertices, + const BufferInfo &vertexInfo, + const Qt3DCore::QNodeId id) +{ + QVector<Qt3DCore::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[0], abc[1], abc[2])); + 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<Qt3DCore::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) +{ +} + +QVector<Qt3DCore::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<Qt3DCore::QBoundingVolume *> > executor; + executor.vertexBufferInfo = vertexBufferInfo; + executor.primitiveType = m_renderer->primitiveType(); + executor.id = id; + + return processBuffer<QVector<Qt3DCore::QBoundingVolume *> >(indexBufferInfo, executor); + + } else { // Non Indexed + + // Check into which type the buffer needs to be casted + VertexExecutor<QVector<Qt3DCore::QBoundingVolume *> > executor; + executor.primitiveType = m_renderer->primitiveType(); + executor.id = id; + + return processBuffer<QVector<Qt3DCore::QBoundingVolume *> >(vertexBufferInfo, executor); + } + } + } + } + return QVector<Qt3DCore::QBoundingVolume *>(); +} + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE |