Ported PLY and STL geometry loaders

Original implementation by Mauro Persano.

Change-Id: I3560fd15239f369de86e514985d0a39b0c6df671
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
This commit is contained in:
Guillermo A. Amaral 2016-10-12 13:18:23 -07:00 committed by Sean Harmer
parent 4338a85487
commit b97213a257
12 changed files with 907 additions and 3 deletions

View File

@ -1,3 +1,3 @@
{
"Keys": ["obj"]
"Keys": ["obj", "ply", "stl"]
}

View File

@ -11,6 +11,8 @@ SOURCES += \
main.cpp \
basegeometryloader.cpp \
objgeometryloader.cpp \
plygeometryloader.cpp \
stlgeometryloader.cpp \
DISTFILES += \
default.json

View File

@ -40,6 +40,8 @@
#include <Qt3DRender/private/qgeometryloaderfactory_p.h>
#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;
}
};

View File

@ -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 <QtCore/QDataStream>
#include <QtCore/QLoggingCategory>
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<int>(type);
}
float readFloatValue(PlyGeometryLoader::DataType type) Q_DECL_OVERRIDE
{
return readValue<float>(type);
}
private:
template <typename T>
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<PlyDataReader> 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<unsigned int> 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

View File

@ -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<Property> 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<Element> m_elements;
bool m_hasNormals;
bool m_hasTexCoords;
};
} // namespace Qt3DRender
QT_END_NAMESPACE
#endif // PLYGEOMETRYLOADER_H

View File

@ -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 <QtCore/QDataStream>
#include <QtCore/QLoggingCategory>
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

View File

@ -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

View File

@ -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
{

View File

@ -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

Binary file not shown.

View File

@ -1,5 +1,7 @@
<RCC>
<qresource prefix="/">
<file>cube.obj</file>
<file>cube.ply</file>
<file>cube.stl</file>
</qresource>
</RCC>

View File

@ -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<QGeometryLoaderInterface> loader;
loader.reset(qLoadPlugin<QGeometryLoaderInterface, QGeometryLoaderFactory>(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<QGeometryLoaderInterface> loader;
loader.reset(qLoadPlugin<QGeometryLoaderInterface, QGeometryLoaderFactory>(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"