/**************************************************************************** ** ** 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 #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::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) { } 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; return processBuffer >(vertexBufferInfo, executor); } } } } return QVector(); } } // namespace Render } // namespace Qt3DRender QT_END_NAMESPACE