mirror of https://github.com/qt/qt3d.git
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:
parent
4338a85487
commit
b97213a257
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"Keys": ["obj"]
|
||||
"Keys": ["obj", "ply", "stl"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ SOURCES += \
|
|||
main.cpp \
|
||||
basegeometryloader.cpp \
|
||||
objgeometryloader.cpp \
|
||||
plygeometryloader.cpp \
|
||||
stlgeometryloader.cpp \
|
||||
|
||||
DISTFILES += \
|
||||
default.json
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
|
@ -1,5 +1,7 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>cube.obj</file>
|
||||
<file>cube.ply</file>
|
||||
<file>cube.stl</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue