From b97213a2575b16717e1d7a0ca8235b8884a240bd Mon Sep 17 00:00:00 2001 From: "Guillermo A. Amaral" Date: Wed, 12 Oct 2016 13:18:23 -0700 Subject: [PATCH] Ported PLY and STL geometry loaders Original implementation by Mauro Persano. Change-Id: I3560fd15239f369de86e514985d0a39b0c6df671 Reviewed-by: Sean Harmer --- .../geometryloaders/default/default.json | 2 +- .../geometryloaders/default/default.pro | 2 + src/plugins/geometryloaders/default/main.cpp | 10 +- .../default/plygeometryloader.cpp | 429 ++++++++++++++++++ .../default/plygeometryloader.h | 135 ++++++ .../default/stlgeometryloader.cpp | 136 ++++++ .../default/stlgeometryloader.h | 76 ++++ src/render/io/qgeometryloaderfactory_p.h | 2 +- tests/auto/render/geometryloaders/cube.ply | 43 ++ tests/auto/render/geometryloaders/cube.stl | Bin 0 -> 684 bytes .../geometryloaders/geometryloaders.qrc | 2 + .../geometryloaders/tst_geometryloaders.cpp | 73 +++ 12 files changed, 907 insertions(+), 3 deletions(-) create mode 100644 src/plugins/geometryloaders/default/plygeometryloader.cpp create mode 100644 src/plugins/geometryloaders/default/plygeometryloader.h create mode 100644 src/plugins/geometryloaders/default/stlgeometryloader.cpp create mode 100644 src/plugins/geometryloaders/default/stlgeometryloader.h create mode 100644 tests/auto/render/geometryloaders/cube.ply create mode 100644 tests/auto/render/geometryloaders/cube.stl diff --git a/src/plugins/geometryloaders/default/default.json b/src/plugins/geometryloaders/default/default.json index 034198a63..2c2e488f7 100644 --- a/src/plugins/geometryloaders/default/default.json +++ b/src/plugins/geometryloaders/default/default.json @@ -1,3 +1,3 @@ { - "Keys": ["obj"] + "Keys": ["obj", "ply", "stl"] } diff --git a/src/plugins/geometryloaders/default/default.pro b/src/plugins/geometryloaders/default/default.pro index 35286ac40..6b5ae8f27 100644 --- a/src/plugins/geometryloaders/default/default.pro +++ b/src/plugins/geometryloaders/default/default.pro @@ -11,6 +11,8 @@ SOURCES += \ main.cpp \ basegeometryloader.cpp \ objgeometryloader.cpp \ + plygeometryloader.cpp \ + stlgeometryloader.cpp \ DISTFILES += \ default.json diff --git a/src/plugins/geometryloaders/default/main.cpp b/src/plugins/geometryloaders/default/main.cpp index 90a46075a..5e7f69f38 100644 --- a/src/plugins/geometryloaders/default/main.cpp +++ b/src/plugins/geometryloaders/default/main.cpp @@ -40,6 +40,8 @@ #include #include "objgeometryloader.h" +#include "plygeometryloader.h" +#include "stlgeometryloader.h" QT_BEGIN_NAMESPACE @@ -51,13 +53,19 @@ public: QStringList keys() const Q_DECL_OVERRIDE { - return QStringList() << OBJGEOMETRYLOADER_EXT; + return QStringList() << OBJGEOMETRYLOADER_EXT + << PLYGEOMETRYLOADER_EXT + << STLGEOMETRYLOADER_EXT; } Qt3DRender::QGeometryLoaderInterface *create(const QString &ext) Q_DECL_OVERRIDE { if (ext.compare(OBJGEOMETRYLOADER_EXT, Qt::CaseInsensitive) == 0) return new Qt3DRender::ObjGeometryLoader; + else if (ext.compare(PLYGEOMETRYLOADER_EXT, Qt::CaseInsensitive) == 0) + return new Qt3DRender::PlyGeometryLoader; + else if (ext.compare(STLGEOMETRYLOADER_EXT, Qt::CaseInsensitive) == 0) + return new Qt3DRender::StlGeometryLoader; return nullptr; } }; diff --git a/src/plugins/geometryloaders/default/plygeometryloader.cpp b/src/plugins/geometryloaders/default/plygeometryloader.cpp new file mode 100644 index 000000000..a7c252174 --- /dev/null +++ b/src/plugins/geometryloaders/default/plygeometryloader.cpp @@ -0,0 +1,429 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "plygeometryloader.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +Q_LOGGING_CATEGORY(PlyGeometryLoaderLog, "Qt3D.PlyGeometryLoader") + +namespace { + +class PlyDataReader +{ +public: + virtual ~PlyDataReader() {} + + virtual int readIntValue(PlyGeometryLoader::DataType type) = 0; + virtual float readFloatValue(PlyGeometryLoader::DataType type) = 0; +}; + +class AsciiPlyDataReader : public PlyDataReader +{ +public: + AsciiPlyDataReader(QIODevice *ioDev) + : m_stream(ioDev) + { } + + int readIntValue(PlyGeometryLoader::DataType) Q_DECL_OVERRIDE + { + int value; + m_stream >> value; + return value; + } + + float readFloatValue(PlyGeometryLoader::DataType) Q_DECL_OVERRIDE + { + float value; + m_stream >> value; + return value; + } + +private: + QTextStream m_stream; +}; + +class BinaryPlyDataReader : public PlyDataReader +{ +public: + BinaryPlyDataReader(QIODevice *ioDev, QDataStream::ByteOrder byteOrder) + : m_stream(ioDev) + { + ioDev->setTextModeEnabled(false); + m_stream.setByteOrder(byteOrder); + } + + int readIntValue(PlyGeometryLoader::DataType type) Q_DECL_OVERRIDE + { + return readValue(type); + } + + float readFloatValue(PlyGeometryLoader::DataType type) Q_DECL_OVERRIDE + { + return readValue(type); + } + +private: + template + T readValue(PlyGeometryLoader::DataType type) + { + switch (type) { + case PlyGeometryLoader::Int8: + { + qint8 value; + m_stream >> value; + return value; + } + + case PlyGeometryLoader::Uint8: + { + quint8 value; + m_stream >> value; + return value; + } + + case PlyGeometryLoader::Int16: + { + qint16 value; + m_stream >> value; + return value; + } + + case PlyGeometryLoader::Uint16: + { + quint16 value; + m_stream >> value; + return value; + } + + case PlyGeometryLoader::Int32: + { + qint32 value; + m_stream >> value; + return value; + } + + case PlyGeometryLoader::Uint32: + { + quint32 value; + m_stream >> value; + return value; + } + + case PlyGeometryLoader::Float32: + { + m_stream.setFloatingPointPrecision(QDataStream::SinglePrecision); + float value; + m_stream >> value; + return value; + } + + case PlyGeometryLoader::Float64: + { + m_stream.setFloatingPointPrecision(QDataStream::DoublePrecision); + double value; + m_stream >> value; + return value; + } + + default: + break; + } + + return 0; + } + + QDataStream m_stream; +}; + +} + +static PlyGeometryLoader::DataType toPlyDataType(const QString &typeName) +{ + if (typeName == QStringLiteral("int8") || typeName == QStringLiteral("char")) { + return PlyGeometryLoader::Int8; + } else if (typeName == QStringLiteral("uint8") || typeName == QStringLiteral("uchar")) { + return PlyGeometryLoader::Uint8; + } else if (typeName == QStringLiteral("int16") || typeName == QStringLiteral("short")) { + return PlyGeometryLoader::Int16; + } else if (typeName == QStringLiteral("uint16") || typeName == QStringLiteral("ushort")) { + return PlyGeometryLoader::Uint16; + } else if (typeName == QStringLiteral("int32") || typeName == QStringLiteral("int")) { + return PlyGeometryLoader::Int32; + } else if (typeName == QStringLiteral("uint32") || typeName == QStringLiteral("uint")) { + return PlyGeometryLoader::Uint32; + } else if (typeName == QStringLiteral("float32") || typeName == QStringLiteral("float")) { + return PlyGeometryLoader::Float32; + } else if (typeName == QStringLiteral("float64") || typeName == QStringLiteral("double")) { + return PlyGeometryLoader::Float64; + } else if (typeName == QStringLiteral("list")) { + return PlyGeometryLoader::TypeList; + } else { + return PlyGeometryLoader::TypeUnknown; + } +} + +bool PlyGeometryLoader::doLoad(QIODevice *ioDev, const QString &subMesh) +{ + Q_UNUSED(subMesh); + + if (!parseHeader(ioDev)) + return false; + + if (!parseMesh(ioDev)) + return false; + + return true; +} + +bool PlyGeometryLoader::parseHeader(QIODevice *ioDev) +{ + Format format = FormatUnknown; + + m_hasNormals = m_hasTexCoords = false; + + while (!ioDev->atEnd()) { + QByteArray lineBuffer = ioDev->readLine(); + QTextStream textStream(lineBuffer, QIODevice::ReadOnly); + + QString token; + textStream >> token; + + if (token == QStringLiteral("end_header")) { + break; + } else if (token == QStringLiteral("format")) { + QString formatName; + textStream >> formatName; + + if (formatName == QStringLiteral("ascii")) { + m_format = FormatAscii; + } else if (formatName == QStringLiteral("binary_little_endian")) { + m_format = FormatBinaryLittleEndian; + } else if (formatName == QStringLiteral("binary_big_endian")) { + m_format = FormatBinaryBigEndian; + } else { + qCDebug(PlyGeometryLoaderLog) << "Unrecognized PLY file format" << format; + return false; + } + } else if (token == QStringLiteral("element")) { + Element element; + + QString elementName; + textStream >> elementName; + + if (elementName == QStringLiteral("vertex")) { + element.type = ElementVertex; + } else if (elementName == QStringLiteral("face")) { + element.type = ElementFace; + } else { + element.type = ElementUnknown; + } + + textStream >> element.count; + + m_elements.append(element); + } else if (token == QStringLiteral("property")) { + if (m_elements.isEmpty()) { + qCDebug(PlyGeometryLoaderLog) << "Misplaced property in header"; + return false; + } + + Property property; + + QString dataTypeName; + textStream >> dataTypeName; + + property.dataType = toPlyDataType(dataTypeName); + + if (property.dataType == TypeList) { + QString listSizeTypeName; + textStream >> listSizeTypeName; + + property.listSizeType = toPlyDataType(listSizeTypeName); + + QString listElementTypeName; + textStream >> listElementTypeName; + + property.listElementType = toPlyDataType(listElementTypeName); + } + + QString propertyName; + textStream >> propertyName; + + if (propertyName == QStringLiteral("vertex_index")) { + property.type = PropertyVertexIndex; + } else if (propertyName == QStringLiteral("x")) { + property.type = PropertyX; + } else if (propertyName == QStringLiteral("y")) { + property.type = PropertyY; + } else if (propertyName == QStringLiteral("z")) { + property.type = PropertyZ; + } else if (propertyName == QStringLiteral("nx")) { + property.type = PropertyNormalX; + m_hasNormals = true; + } else if (propertyName == QStringLiteral("ny")) { + property.type = PropertyNormalY; + m_hasNormals = true; + } else if (propertyName == QStringLiteral("nz")) { + property.type = PropertyNormalZ; + m_hasNormals = true; + } else if (propertyName == QStringLiteral("s")) { + property.type = PropertyTextureU; + m_hasTexCoords = true; + } else if (propertyName == QStringLiteral("t")) { + property.type = PropertyTextureV; + m_hasTexCoords = true; + } else { + property.type = PropertyUnknown; + } + + Element &element = m_elements.last(); + element.properties.append(property); + } + } + + if (m_format == FormatUnknown) { + qCDebug(PlyGeometryLoaderLog) << "Missing PLY file format"; + return false; + } + + return true; +} + +bool PlyGeometryLoader::parseMesh(QIODevice *ioDev) +{ + QScopedPointer dataReader; + + switch (m_format) { + case FormatAscii: + dataReader.reset(new AsciiPlyDataReader(ioDev)); + break; + + case FormatBinaryLittleEndian: + dataReader.reset(new BinaryPlyDataReader(ioDev, QDataStream::LittleEndian)); + break; + + default: + dataReader.reset(new BinaryPlyDataReader(ioDev, QDataStream::BigEndian)); + break; + } + + for (auto &element : qAsConst(m_elements)) { + if (element.type == ElementVertex) { + m_points.reserve(element.count); + + if (m_hasNormals) + m_normals.reserve(element.count); + + if (m_hasTexCoords) + m_texCoords.reserve(element.count); + } + + for (int i = 0; i < element.count; ++i) { + QVector3D point; + QVector3D normal; + QVector2D texCoord; + + QVector faceIndices; + + for (auto &property : element.properties) { + if (property.dataType == TypeList) { + const int listSize = dataReader->readIntValue(property.listSizeType); + + if (element.type == ElementFace) + faceIndices.reserve(listSize); + + for (int j = 0; j < listSize; ++j) { + const unsigned int value = dataReader->readIntValue(property.listElementType); + + if (element.type == ElementFace) + faceIndices.append(value); + } + } else { + float value = dataReader->readFloatValue(property.dataType); + + if (element.type == ElementVertex) { + switch (property.type) { + case PropertyX: point.setX(value); break; + case PropertyY: point.setY(value); break; + case PropertyZ: point.setZ(value); break; + case PropertyNormalX: normal.setX(value); break; + case PropertyNormalY: normal.setY(value); break; + case PropertyNormalZ: normal.setZ(value); break; + case PropertyTextureU: texCoord.setX(value); break; + case PropertyTextureV: texCoord.setY(value); break; + default: break; + } + } + } + } + + if (element.type == ElementVertex) { + m_points.append(point); + + if (m_hasNormals) + m_normals.append(normal); + + if (m_hasTexCoords) + m_texCoords.append(texCoord); + } else if (element.type == ElementFace) { + if (faceIndices.size() >= 3) { + // decompose face into triangle fan + + for (int j = 1; j < faceIndices.size() - 1; ++j) { + m_indices.append(faceIndices[0]); + m_indices.append(faceIndices[j]); + m_indices.append(faceIndices[j + 1]); + } + } + } + } + } + + return true; +} + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/plugins/geometryloaders/default/plygeometryloader.h b/src/plugins/geometryloaders/default/plygeometryloader.h new file mode 100644 index 000000000..e044529d4 --- /dev/null +++ b/src/plugins/geometryloaders/default/plygeometryloader.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLYGEOMETRYLOADER_H +#define PLYGEOMETRYLOADER_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 "basegeometryloader_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +#define PLYGEOMETRYLOADER_EXT QLatin1String("ply") + +class PlyGeometryLoader : public BaseGeometryLoader +{ +public: + enum DataType { + Int8, + Uint8, + Int16, + Uint16, + Int32, + Uint32, + Float32, + Float64, + TypeList, + TypeUnknown + }; + + enum PropertyType { + PropertyVertexIndex, + PropertyX, + PropertyY, + PropertyZ, + PropertyNormalX, + PropertyNormalY, + PropertyNormalZ, + PropertyTextureU, + PropertyTextureV, + PropertyUnknown, + }; + + enum Format { + FormatAscii, + FormatBinaryLittleEndian, + FormatBinaryBigEndian, + FormatUnknown, + }; + + enum ElementType { + ElementVertex, + ElementFace, + ElementUnknown, + }; + + struct Property { + PropertyType type; + DataType dataType; + DataType listSizeType; + DataType listElementType; + }; + + struct Element { + ElementType type; + int count; + QList properties; + }; + +protected: + bool doLoad(QIODevice *ioDev, const QString &subMesh) Q_DECL_FINAL; + +private: + bool parseHeader(QIODevice *ioDev); + bool parseMesh(QIODevice *ioDev); + + Format m_format; + QList m_elements; + + bool m_hasNormals; + bool m_hasTexCoords; +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // PLYGEOMETRYLOADER_H diff --git a/src/plugins/geometryloaders/default/stlgeometryloader.cpp b/src/plugins/geometryloaders/default/stlgeometryloader.cpp new file mode 100644 index 000000000..b76698cc7 --- /dev/null +++ b/src/plugins/geometryloaders/default/stlgeometryloader.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "stlgeometryloader.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +Q_LOGGING_CATEGORY(StlGeometryLoaderLog, "Qt3D.StlGeometryLoader") + +bool StlGeometryLoader::doLoad(QIODevice *ioDev, const QString &subMesh) +{ + char signature[5]; + + Q_UNUSED(subMesh); + + if (ioDev->peek(signature, sizeof(signature)) != sizeof(signature)) + return false; + + if (!qstrncmp(signature, "solid", 5)) + return loadAscii(ioDev); + else + return loadBinary(ioDev); + + return true; +} + +bool StlGeometryLoader::loadAscii(QIODevice *ioDev) +{ + // TODO stricter syntax checking + + while (!ioDev->atEnd()) { + QByteArray lineBuffer = ioDev->readLine(); + + const char *begin = lineBuffer.constData(); + const char *end = begin + lineBuffer.size(); + + const ByteArraySplitter tokens(begin, end, ' ', QString::SkipEmptyParts); + + if (qstrncmp(tokens.charPtrAt(0), "vertex ", 7) == 0) { + if (tokens.size() < 4) { + qCWarning(StlGeometryLoaderLog) << "Unsupported number of components in vertex"; + } else { + const float x = tokens.floatAt(1); + const float y = tokens.floatAt(2); + const float z = tokens.floatAt(3); + m_points.append(QVector3D(x, y, z)); + m_indices.append(m_indices.size()); + } + } + } + + return true; +} + +bool StlGeometryLoader::loadBinary(QIODevice *ioDev) +{ + static const int headerSize = 80; + + if (ioDev->read(headerSize).size() != headerSize) + return false; + + ioDev->setTextModeEnabled(false); + + QDataStream stream(ioDev); + stream.setByteOrder(QDataStream::LittleEndian); + stream.setFloatingPointPrecision(QDataStream::SinglePrecision); + + quint32 triangleCount; + stream >> triangleCount; + + m_points.reserve(triangleCount * 3); + m_indices.reserve(triangleCount * 3); + + for (unsigned i = 0; i < triangleCount; ++i) { + QVector3D normal; + stream >> normal; + + for (int j = 0; j < 3; ++j) { + QVector3D point; + stream >> point; + m_points.append(point); + + m_indices.append((i * 3) + j); + } + + quint16 attributeCount; + stream >> attributeCount; + } + + return true; +} + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/plugins/geometryloaders/default/stlgeometryloader.h b/src/plugins/geometryloaders/default/stlgeometryloader.h new file mode 100644 index 000000000..20af85a5d --- /dev/null +++ b/src/plugins/geometryloaders/default/stlgeometryloader.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef STLGEOMETRYLOADER_H +#define STLGEOMETRYLOADER_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 "basegeometryloader_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +#define STLGEOMETRYLOADER_EXT QLatin1String("stl") + +class StlGeometryLoader : public BaseGeometryLoader +{ +protected: + bool doLoad(QIODevice *ioDev, const QString &subMesh) Q_DECL_FINAL; + +private: + bool loadAscii(QIODevice *ioDev); + bool loadBinary(QIODevice *ioDev); +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // STLGEOMETRYLOADER_H diff --git a/src/render/io/qgeometryloaderfactory_p.h b/src/render/io/qgeometryloaderfactory_p.h index f6ede7610..c6a7344ce 100644 --- a/src/render/io/qgeometryloaderfactory_p.h +++ b/src/render/io/qgeometryloaderfactory_p.h @@ -63,7 +63,7 @@ namespace Qt3DRender { #define QGeometryLoaderFactory_iid "org.qt-project.Qt3DRender.QGeometryLoaderFactory 5.8" -struct QGeometryLoaderInterface; +class QGeometryLoaderInterface; class QT3DRENDERSHARED_PRIVATE_EXPORT QGeometryLoaderFactory : public QObject, public QFactoryInterface { diff --git a/tests/auto/render/geometryloaders/cube.ply b/tests/auto/render/geometryloaders/cube.ply new file mode 100644 index 000000000..295e39fb5 --- /dev/null +++ b/tests/auto/render/geometryloaders/cube.ply @@ -0,0 +1,43 @@ +ply +format ascii 1.0 +comment Created by Blender 2.77 (sub 0) - www.blender.org, source file: '' +element vertex 24 +property float x +property float y +property float z +property float nx +property float ny +property float nz +element face 6 +property list uchar uint vertex_indices +end_header +1.000000 1.000000 -1.000000 0.000000 0.000000 -1.000000 +1.000000 -1.000000 -1.000000 0.000000 0.000000 -1.000000 +-1.000000 -1.000000 -1.000000 0.000000 0.000000 -1.000000 +-1.000000 1.000000 -1.000000 0.000000 0.000000 -1.000000 +1.000000 0.999999 1.000000 0.000000 -0.000000 1.000000 +-1.000000 1.000000 1.000000 0.000000 -0.000000 1.000000 +-1.000000 -1.000000 1.000000 0.000000 -0.000000 1.000000 +0.999999 -1.000001 1.000000 0.000000 -0.000000 1.000000 +1.000000 1.000000 -1.000000 1.000000 -0.000000 0.000000 +1.000000 0.999999 1.000000 1.000000 -0.000000 0.000000 +0.999999 -1.000001 1.000000 1.000000 -0.000000 0.000000 +1.000000 -1.000000 -1.000000 1.000000 -0.000000 0.000000 +1.000000 -1.000000 -1.000000 -0.000000 -1.000000 -0.000000 +0.999999 -1.000001 1.000000 -0.000000 -1.000000 -0.000000 +-1.000000 -1.000000 1.000000 -0.000000 -1.000000 -0.000000 +-1.000000 -1.000000 -1.000000 -0.000000 -1.000000 -0.000000 +-1.000000 -1.000000 -1.000000 -1.000000 0.000000 -0.000000 +-1.000000 -1.000000 1.000000 -1.000000 0.000000 -0.000000 +-1.000000 1.000000 1.000000 -1.000000 0.000000 -0.000000 +-1.000000 1.000000 -1.000000 -1.000000 0.000000 -0.000000 +1.000000 0.999999 1.000000 0.000000 1.000000 0.000000 +1.000000 1.000000 -1.000000 0.000000 1.000000 0.000000 +-1.000000 1.000000 -1.000000 0.000000 1.000000 0.000000 +-1.000000 1.000000 1.000000 0.000000 1.000000 0.000000 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 +4 12 13 14 15 +4 16 17 18 19 +4 20 21 22 23 diff --git a/tests/auto/render/geometryloaders/cube.stl b/tests/auto/render/geometryloaders/cube.stl new file mode 100644 index 0000000000000000000000000000000000000000..e091f0b36e269925d38da98469d12fc34f954aa8 GIT binary patch literal 684 zcmb7>K~BRk5Ji8}vf~bTSr#BfEp-_QsrNvrVFeV0B6XMCpjY4qEJ)Ysr4SNQYyLPj z{b7eC%Z_K>|1*=>>UmKvi@Ccm7mx1dp?I1X<;C^obn3=0uXpb19RFIU%pL$A9aOhK zorh56JmdXvwgZ0eLS=8lnjop*GW+|NrAcS|{kNox!t4T^g25hXmA-2)O?zWZw+sBsEwJbm* zIyc5yd8ZVsYBSWHUX5lct#j)LPT23lS)&pCAF2e5aO=%A!<*On*jwsWX<#4LkuW!n Is9#^{2fKIKHvj+t literal 0 HcmV?d00001 diff --git a/tests/auto/render/geometryloaders/geometryloaders.qrc b/tests/auto/render/geometryloaders/geometryloaders.qrc index 597a56e5e..a2418d2fd 100644 --- a/tests/auto/render/geometryloaders/geometryloaders.qrc +++ b/tests/auto/render/geometryloaders/geometryloaders.qrc @@ -1,5 +1,7 @@ cube.obj + cube.ply + cube.stl diff --git a/tests/auto/render/geometryloaders/tst_geometryloaders.cpp b/tests/auto/render/geometryloaders/tst_geometryloaders.cpp index a51364e0e..61910c417 100644 --- a/tests/auto/render/geometryloaders/tst_geometryloaders.cpp +++ b/tests/auto/render/geometryloaders/tst_geometryloaders.cpp @@ -59,6 +59,8 @@ class tst_geometryloaders : public QObject private Q_SLOTS: void testOBJLoader(); + void testPLYLoader(); + void testSTLLoader(); }; void tst_geometryloaders::testOBJLoader() @@ -100,6 +102,77 @@ void tst_geometryloaders::testOBJLoader() file.close(); } +void tst_geometryloaders::testPLYLoader() +{ + QScopedPointer loader; + loader.reset(qLoadPlugin(geometryLoader(), QStringLiteral("ply"))); + QVERIFY(loader); + if (!loader) + return; + + QFile file(QStringLiteral(":/cube.ply")); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug("Could not open test file for reading"); + return; + } + + bool loaded = loader->load(&file, QStringLiteral("Cube")); + QVERIFY(loaded); + if (!loaded) + return; + + QGeometry *geometry = loader->geometry(); + QVERIFY(geometry); + if (!geometry) + return; + + QCOMPARE(geometry->attributes().count(), 3); + for (QAttribute *attr : geometry->attributes()) { + switch (attr->attributeType()) { + case QAttribute::IndexAttribute: + QCOMPARE(attr->count(), 36u); + break; + case QAttribute::VertexAttribute: + QCOMPARE(attr->count(), 24u); + break; + } + } + + file.close(); +} + +void tst_geometryloaders::testSTLLoader() +{ + QScopedPointer loader; + loader.reset(qLoadPlugin(geometryLoader(), QStringLiteral("stl"))); + QVERIFY(loader); + if (!loader) + return; + + QFile file(QStringLiteral(":/cube.stl")); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug("Could not open test file for reading"); + return; + } + + bool loaded = loader->load(&file, QStringLiteral("Cube")); + QVERIFY(loaded); + if (!loaded) + return; + + QGeometry *geometry = loader->geometry(); + QVERIFY(geometry); + if (!geometry) + return; + + QCOMPARE(geometry->attributes().count(), 3); + for (QAttribute *attr : geometry->attributes()) { + QCOMPARE(attr->count(), 36u); + } + + file.close(); +} + QTEST_MAIN(tst_geometryloaders) #include "tst_geometryloaders.moc"