diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2014-08-19 15:26:49 +0200 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2014-08-19 17:50:57 +0200 |
commit | 672b3e47299f6ba0034f73b252d0436b55fb3085 (patch) | |
tree | 262af0ce0f4b7b30a5788fd626c2a4cd01f3abc0 /src/plugins | |
parent | 4a8af6979a8808a3044ca21dbbb087e94a6fa268 (diff) |
Assimp external dependency
The AssimpParser is now a SceneParser plugin that is build if config tests for
assimp succeed.
Change-Id: I0e3f6a6ce2a43298b71b0261084f6c79521f214d
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/sceneparsers/assimp/assimp.pri | 9 | ||||
-rw-r--r-- | src/plugins/sceneparsers/assimp/assimp.pro | 16 | ||||
-rw-r--r-- | src/plugins/sceneparsers/assimp/assimphelpers.cpp | 233 | ||||
-rw-r--r-- | src/plugins/sceneparsers/assimp/assimphelpers_p.h | 95 | ||||
-rw-r--r-- | src/plugins/sceneparsers/assimp/assimpparser.cpp | 862 | ||||
-rw-r--r-- | src/plugins/sceneparsers/assimp/assimpparser_p.h | 145 | ||||
-rw-r--r-- | src/plugins/sceneparsers/sceneparsers.pro | 5 |
7 files changed, 1365 insertions, 0 deletions
diff --git a/src/plugins/sceneparsers/assimp/assimp.pri b/src/plugins/sceneparsers/assimp/assimp.pri new file mode 100644 index 000000000..89074c9d3 --- /dev/null +++ b/src/plugins/sceneparsers/assimp/assimp.pri @@ -0,0 +1,9 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/assimpparser_p.h \ + $$PWD/assimphelpers_p.h + +SOURCES += \ + $$PWD/assimpparser.cpp \ + $$PWD/assimphelpers.cpp diff --git a/src/plugins/sceneparsers/assimp/assimp.pro b/src/plugins/sceneparsers/assimp/assimp.pro new file mode 100644 index 000000000..9d04cefc6 --- /dev/null +++ b/src/plugins/sceneparsers/assimp/assimp.pro @@ -0,0 +1,16 @@ +TARGET = assimpsceneparser +MODULE = 3drenderer +QT += core-private 3dcore 3dcore-private 3drenderer 3drenderer-private + +PLUGIN_TYPE = sceneparsers +PLUGIN_CLASS_NAME = AssimpParser +load(qt_plugin) + +include(assimp.pri) + +LIBS += -lassimp + +unix { + CONFIG += link_pkgconfig + PKGCONFIG += assimp +} diff --git a/src/plugins/sceneparsers/assimp/assimphelpers.cpp b/src/plugins/sceneparsers/assimp/assimphelpers.cpp new file mode 100644 index 000000000..4310d6764 --- /dev/null +++ b/src/plugins/sceneparsers/assimp/assimphelpers.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 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 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "assimphelpers_p.h" + +#include <QFileInfo> +#include <QUrl> +#include <QDir> +#include <QDebug> +#include <QMap> + +QT_BEGIN_NAMESPACE + +namespace Qt3D { +namespace AssimpHelper { +/*! + * \class AssimpIOStream + * + * \internal + * + * \brief Provides a custom file stream class to be used by AssimpIOSystem. + * + */ + +/*! + * Builds a new AssimpIOStream instance. + */ +AssimpIOStream::AssimpIOStream(QIODevice *device) : + Assimp::IOStream(), + m_device(device) +{ +} + +/*! + * Clears an AssimpIOStream instance before deletion. + */ +AssimpIOStream::~AssimpIOStream() +{ + // Owns m_device + if (m_device && m_device->isOpen()) { + m_device->close(); + delete m_device; + } +} + +/*! + * Reads at most \a pCount elements of \a pSize bytes of data into \a pvBuffer. + * Returns the number of bytes read or -1 if an error occurred. + */ +size_t AssimpIOStream::Read(void *pvBuffer, size_t pSize, size_t pCount) +{ + qint64 readBytes = m_device->read((char *)pvBuffer, pSize * pCount); + if (readBytes < 0) + qWarning() << Q_FUNC_INFO << " Reading failed"; + return readBytes; +} + + +/*! + * Writes \a pCount elements of \a pSize bytes from \a pvBuffer. + * Returns the number of bytes written or -1 if an error occurred. + */ +size_t AssimpIOStream::Write(const void *pvBuffer, size_t pSize, size_t pCount) +{ + qint64 writtenBytes = m_device->write((char *)pvBuffer, pSize * pCount); + if (writtenBytes < 0) + qWarning() << Q_FUNC_INFO << " Writing failed"; + return writtenBytes; +} + +/*! + * Seeks the current file descriptor to a position defined by \a pOrigin and \a pOffset + */ +aiReturn AssimpIOStream::Seek(size_t pOffset, aiOrigin pOrigin) +{ + qint64 seekPos = pOffset; + + if (pOrigin == aiOrigin_CUR) + seekPos += m_device->pos(); + else if (pOrigin == aiOrigin_END) + seekPos += m_device->size(); + + if (!m_device->seek(seekPos)) { + qWarning() << Q_FUNC_INFO << " Seeking failed"; + return aiReturn_FAILURE; + } + return aiReturn_SUCCESS; +} + +/*! + * Returns the current position of the read/write cursor. + */ +size_t AssimpIOStream::Tell() const +{ + return m_device->pos(); +} + +/*! + * Returns the filesize; + */ +size_t AssimpIOStream::FileSize() const +{ + return m_device->size(); +} + +/*! + * Flushes the current device. + */ +void AssimpIOStream::Flush() +{ + // QIODevice has no flush method +} + +/*! + * \class AssimpIOSystem + * + * \internal + * + * \brief Provides a custom file handler to the Assimp importer in order to handle + * various Qt specificities (QResources ...) + * + */ + +/*! + * Builds a new instance of AssimpIOSystem. + */ +AssimpIOSystem::AssimpIOSystem() : + Assimp::IOSystem() +{ + m_openModeMaps[QStringLiteral("r")] = QIODevice::ReadOnly; + m_openModeMaps[QStringLiteral("r+")] = QIODevice::ReadWrite; + m_openModeMaps[QStringLiteral("w")] = QIODevice::WriteOnly|QIODevice::Truncate; + m_openModeMaps[QStringLiteral("w+")] = QIODevice::ReadWrite|QIODevice::Truncate; + m_openModeMaps[QStringLiteral("a")] = QIODevice::WriteOnly|QIODevice::Append; + m_openModeMaps[QStringLiteral("a+")] = QIODevice::ReadWrite|QIODevice::Append; + m_openModeMaps[QStringLiteral("wb")] = QIODevice::WriteOnly; + m_openModeMaps[QStringLiteral("wt")] = QIODevice::WriteOnly; + m_openModeMaps[QStringLiteral("rb")] = QIODevice::ReadOnly; + m_openModeMaps[QStringLiteral("rt")] = QIODevice::ReadOnly; +} + +/*! + * Clears an AssimpIOSystem instance before deletion. + */ +AssimpIOSystem::~AssimpIOSystem() +{ +} + +/*! + * Returns true if the file located at pFile exists, false otherwise. + */ +bool AssimpIOSystem::Exists(const char *pFile) const +{ + return QFileInfo(QString::fromUtf8(pFile)).exists(); +} + +/*! + * Returns the default system separator. + */ +char AssimpIOSystem::getOsSeparator() const +{ + return QDir::separator().toLatin1(); +} + +/*! + * Opens the file located at \a pFile with the opening mode + * specified by \a pMode. + */ +Assimp::IOStream *AssimpIOSystem::Open(const char *pFile, const char *pMode) +{ + QIODevice::OpenMode openMode = QIODevice::NotOpen; + QString cleanedMode = QString::fromUtf8(pMode).trimmed(); + if (m_openModeMaps.contains(cleanedMode)) + openMode = m_openModeMaps[cleanedMode]; + + QFile *file = new QFile(QString::fromUtf8(pFile)); + if (file->open(openMode)) + return new AssimpIOStream(file); + delete file; + return NULL; +} + +/*! + * Closes the Assimp::IOStream \a pFile. + */ +void AssimpIOSystem::Close(Assimp::IOStream *pFile) +{ + // Assimp::IOStream has a virtual destructor which closes the stream + delete pFile; +} + +} // AssimpHelper namespace +} // Qt3D namespace + +QT_END_NAMESPACE diff --git a/src/plugins/sceneparsers/assimp/assimphelpers_p.h b/src/plugins/sceneparsers/assimp/assimphelpers_p.h new file mode 100644 index 000000000..6e0f1fa17 --- /dev/null +++ b/src/plugins/sceneparsers/assimp/assimphelpers_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 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 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ASSIMPHELPERS_H +#define ASSIMPHELPERS_H + +// ASSIMP INCLUDES +#include <assimp/IOStream.hpp> +#include <assimp/IOSystem.hpp> + +#include <QIODevice> +#include <QMap> + +QT_BEGIN_NAMESPACE + +namespace Qt3D { +namespace AssimpHelper { + +//CUSTOM FILE STREAM +class AssimpIOStream : public Assimp::IOStream +{ +public : + AssimpIOStream(QIODevice *device); + ~AssimpIOStream(); + + size_t Read(void *pvBuffer, size_t pSize, size_t pCount) Q_DECL_OVERRIDE; + size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) Q_DECL_OVERRIDE; + aiReturn Seek(size_t pOffset, aiOrigin pOrigin) Q_DECL_OVERRIDE; + size_t Tell() const Q_DECL_OVERRIDE; + size_t FileSize() const ; + void Flush() Q_DECL_OVERRIDE; + +private: + QIODevice *m_device; +}; + +//CUSTOM FILE IMPORTER TO HANDLE QT RESOURCES WITHIN ASSIMP +class AssimpIOSystem : public Assimp::IOSystem +{ +public : + AssimpIOSystem(); + ~AssimpIOSystem(); + bool Exists(const char *pFile) const Q_DECL_OVERRIDE; + char getOsSeparator() const Q_DECL_OVERRIDE; + Assimp::IOStream *Open(const char *pFile, const char *pMode) Q_DECL_OVERRIDE; + void Close(Assimp::IOStream *pFile) Q_DECL_OVERRIDE; + +private: + QMap<QString, QIODevice::OpenMode> m_openModeMaps; +}; + +} // AssimpHelper namespace +} // Qt3D namespace + +QT_END_NAMESPACE + +#endif // ASSIMPHELPERS_H diff --git a/src/plugins/sceneparsers/assimp/assimpparser.cpp b/src/plugins/sceneparsers/assimp/assimpparser.cpp new file mode 100644 index 000000000..9adac2fca --- /dev/null +++ b/src/plugins/sceneparsers/assimp/assimpparser.cpp @@ -0,0 +1,862 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 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 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "assimpparser_p.h" + +#include <Qt3DCore/qentity.h> +#include <Qt3DCore/qtransform.h> +#include <Qt3DCore/qmatrixtransform.h> +#include <Qt3DCore/qcameralens.h> +#include <Qt3DRenderer/qparameter.h> +#include <Qt3DRenderer/qmesh.h> +#include <Qt3DRenderer/qmaterial.h> +#include <Qt3DRenderer/qbuffer.h> +#include <Qt3DRenderer/qattribute.h> +#include <Qt3DRenderer/qtexture.h> +#include <QFileInfo> +#include <QColor> +#include <qmath.h> +#include "renderlogging.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3D { + +/*! + * \class AssimpParser + * \namespace Qt3D + * \since 5.3 + * + * \brief Provides a generic way of loading various 3D assets + * format into a Qt3D scene. + * + * It should be noted that Assimp aiString is explicitly defined to be UTF-8. + * + * \sa GLTFParser +*/ + +Q_LOGGING_CATEGORY(AssimpParserLog, "Qt3D.AssimpParser") + +namespace { + +const QString ASSIMP_MATERIAL_DIFFUSE_COLOR = QStringLiteral("diffuse"); +const QString ASSIMP_MATERIAL_SPECULAR_COLOR = QStringLiteral("specular"); +const QString ASSIMP_MATERIAL_AMBIENT_COLOR = QStringLiteral("ambient"); +const QString ASSIMP_MATERIAL_EMISSIVE_COLOR = QStringLiteral("emissive"); +const QString ASSIMP_MATERIAL_TRANSPARENT_COLOR = QStringLiteral("transparent"); +const QString ASSIMP_MATERIAL_REFLECTIVE_COLOR = QStringLiteral("reflective"); + +const QString ASSIMP_MATERIAL_DIFFUSE_TEXTURE = QStringLiteral("diffuseTex"); +const QString ASSIMP_MATERIAL_AMBIENT_TEXTURE = QStringLiteral("ambientTex"); +const QString ASSIMP_MATERIAL_SPECULAR_TEXTURE = QStringLiteral("specularTex"); +const QString ASSIMP_MATERIAL_EMISSIVE_TEXTURE = QStringLiteral("emissiveTex"); +const QString ASSIMP_MATERIAL_NORMALS_TEXTURE = QStringLiteral("normalsTex"); +const QString ASSIMP_MATERIAL_OPACITY_TEXTURE = QStringLiteral("opacityTex"); +const QString ASSIMP_MATERIAL_REFLECTION_TEXTURE = QStringLiteral("reflectionTex"); +const QString ASSIMP_MATERIAL_HEIGHT_TEXTURE = QStringLiteral("heightTex"); +const QString ASSIMP_MATERIAL_LIGHTMAP_TEXTURE = QStringLiteral("opacityTex"); +const QString ASSIMP_MATERIAL_DISPLACEMENT_TEXTURE = QStringLiteral("displacementTex"); +const QString ASSIMP_MATERIAL_SHININESS_TEXTURE = QStringLiteral("shininessTex"); + +const QString ASSIMP_MATERIAL_IS_TWOSIDED = QStringLiteral("twosided"); +const QString ASSIMP_MATERIAL_IS_WIREFRAME = QStringLiteral("wireframe"); + +const QString ASSIMP_MATERIAL_OPACITY = QStringLiteral("opacity"); +const QString ASSIMP_MATERIAL_SHININESS = QStringLiteral("shininess"); +const QString ASSIMP_MATERIAL_SHININESS_STRENGTH = QStringLiteral("shininess_strength"); +const QString ASSIMP_MATERIAL_REFRACTI = QStringLiteral("refracti"); +const QString ASSIMP_MATERIAL_REFLECTIVITY = QStringLiteral("reflectivity"); + +const QString ASSIMP_MATERIAL_NAME = QStringLiteral("name"); + +const QString VERTICES_ATTRIBUTE_NAME = QAbstractMeshData::defaultPositionAttributeName(); +const QString NORMAL_ATTRIBUTE_NAME = QAbstractMeshData::defaultNormalAttributeName(); +const QString TANGENT_ATTRIBUTE_NAME = QAbstractMeshData::defaultTangentAttributeName(); +const QString TEXTCOORD_ATTRIBUTE_NAME = QAbstractMeshData::defaultTextureCoordinateAttributeName(); +const QString COLOR_ATTRIBUTE_NAME = QAbstractMeshData::defaultColorAttributeName(); + +} + +QStringList AssimpParser::assimpSupportedFormatsList = AssimpParser::assimpSupportedFormats(); + +/*! + * Returns a QStringlist with the suffixes of the various supported asset formats. + */ +QStringList AssimpParser::assimpSupportedFormats() +{ + QStringList formats; + + formats.reserve(60); + formats.append(QStringLiteral("3d")); + formats.append(QStringLiteral("3ds")); + formats.append(QStringLiteral("ac")); + formats.append(QStringLiteral("ac3d")); + formats.append(QStringLiteral("acc")); + formats.append(QStringLiteral("ase")); + formats.append(QStringLiteral("ask")); + formats.append(QStringLiteral("b3d")); + formats.append(QStringLiteral("blend")); + formats.append(QStringLiteral("bvh")); + formats.append(QStringLiteral("cob")); + formats.append(QStringLiteral("csm")); + formats.append(QStringLiteral("dae")); + formats.append(QStringLiteral("dxf")); + formats.append(QStringLiteral("enff")); + formats.append(QStringLiteral("hmp")); + formats.append(QStringLiteral("irr")); + formats.append(QStringLiteral("irrmesh")); + formats.append(QStringLiteral("lwo")); + formats.append(QStringLiteral("lws")); + formats.append(QStringLiteral("lxo")); + formats.append(QStringLiteral("md2")); + formats.append(QStringLiteral("md3")); + formats.append(QStringLiteral("md5anim")); + formats.append(QStringLiteral("md5camera")); + formats.append(QStringLiteral("md5mesh")); + formats.append(QStringLiteral("mdc")); + formats.append(QStringLiteral("mdl")); + formats.append(QStringLiteral("mesh.xml")); + formats.append(QStringLiteral("mot")); + formats.append(QStringLiteral("ms3d")); + formats.append(QStringLiteral("ndo")); + formats.append(QStringLiteral("nff")); + formats.append(QStringLiteral("obj")); + formats.append(QStringLiteral("off")); + formats.append(QStringLiteral("pk3")); + formats.append(QStringLiteral("ply")); + formats.append(QStringLiteral("prj")); + formats.append(QStringLiteral("q3o")); + formats.append(QStringLiteral("q3s")); + formats.append(QStringLiteral("raw")); + formats.append(QStringLiteral("scn")); + formats.append(QStringLiteral("smd")); + formats.append(QStringLiteral("stl")); + formats.append(QStringLiteral("ter")); + formats.append(QStringLiteral("uc")); + formats.append(QStringLiteral("vta")); + formats.append(QStringLiteral("x")); + formats.append(QStringLiteral("xml")); + + return formats; +} + +class AssimpMesh : public QAbstractMesh +{ + Q_OBJECT +public : + explicit AssimpMesh(QNode *parent = 0); + void copy(const QNode *ref) Q_DECL_OVERRIDE; + + QAbstractMeshFunctorPtr meshFunctor() const Q_DECL_OVERRIDE; + void setData(QMeshDataPtr data); + +private: + QMeshDataPtr m_meshData; + AssimpMesh *doClone(QNode *clonedParent) const Q_DECL_OVERRIDE; + + class AssimpMeshFunctor : public QAbstractMeshFunctor + { + public: + explicit AssimpMeshFunctor(QMeshDataPtr meshData); + QAbstractMeshDataPtr operator()() Q_DECL_OVERRIDE; + private: + QMeshDataPtr m_meshData; + }; +}; + +/*! + * Initialized a new instance of AssimpParser. + */ +AssimpParser::AssimpParser() : AbstractSceneParser(), + m_aiScene(0), + m_sceneParsed(false) +{ +} + +/*! + * Cleans the parser properly before destruction. + */ +AssimpParser::~AssimpParser() +{ + cleanup(); +} + +/*! + * Return true if the provided \a path has a suffix supported + * by the Assimp Assets importer. + */ +bool AssimpParser::isAssimpPath(const QString& path) +{ + QFileInfo fileInfo(path); + + if (!fileInfo.exists() || + !AssimpParser::assimpSupportedFormats().contains(fileInfo.suffix().toLower())) + return false; + return true; +} + +/*! + * Returns a QMatrix4x4 from \a matrix; + */ +QMatrix4x4 AssimpParser::aiMatrix4x4ToQMatrix4x4(const aiMatrix4x4 &matrix) +{ + return QMatrix4x4(matrix.a1, matrix.a2, matrix.a3, matrix.a4, + matrix.b1, matrix.b2, matrix.b3, matrix.b4, + matrix.c1, matrix.c2, matrix.c3, matrix.c4, + matrix.d1, matrix.d2, matrix.d3, matrix.d4); +} + +/*! + * Sets the \a path used by the parser to load the asset file. + * If the file is valid, this will trigger the parsing of the file. + */ +void AssimpParser::setFilePath(const QString& path) +{ + QFileInfo file(path); + m_sceneDir = file.absoluteDir(); + if (!file.exists()) { + qCWarning(AssimpParserLog) << "File missing " << path; + return ; + } + readSceneFile(path); +} + +/*! + * Returns true if the extension of \a path is supported by + * the assimp parser. + */ +bool AssimpParser::isPathExtensionSupported(const QString &path) +{ + return AssimpParser::isAssimpPath(path); +} + +/*! + * Returns a Entity node which is the root node of the scene + * node specified by \a id. If \a id is empty, the scene is assumed to be + * the root node of the scene. + * + * Returns Q_NULLPTR if \a id was specified but not node matching it can be found. + */ +QEntity *AssimpParser::scene(QString id) +{ + // m_aiScene shouldn't be null. + // If it is either, the file failed to be imported or + // setFilePath was not called + if (m_aiScene.isNull()) + return Q_NULLPTR; + + aiNode *rootNode = m_aiScene->mRootNode; + // if id specified, tries to find node + if (!id.isEmpty() && + !(rootNode = rootNode->FindNode(id.toUtf8().constData()))) { + qCDebug(AssimpParserLog) << Q_FUNC_INFO << " Couldn't find requested scene node"; + return Q_NULLPTR; + } + + // Builds the Qt3D scene using the Assimp aiScene + // and the various dicts filled previously by parse + return node(rootNode); +} + +/*! + * Returns a Node from the scene identified by \a id. + * Returns Q_NULLPTR if no node can be found. + */ +QEntity *AssimpParser::node(QString id) +{ + if (m_aiScene.isNull()) + return Q_NULLPTR; + parse(); + aiNode *n = m_aiScene->mRootNode->FindNode(id.toUtf8().constData()); + return node(n); +} + +/*! + * Returns a Node from an Assimp aiNode \a node. + */ +QEntity *AssimpParser::node(aiNode *node) +{ + if (node == Q_NULLPTR) + return Q_NULLPTR; + QEntity *entityNode = new QEntity(); + + // Add Meshes to the node + for (uint i = 0; i < node->mNumMeshes; i++) { + uint meshIdx = node->mMeshes[i]; + AssimpMesh * mesh = m_meshes[meshIdx]; + // mesh material + if (m_materials.contains(meshIdx)) + entityNode->addComponent(m_materials[meshIdx]); + // mesh + entityNode->addComponent(mesh); + } + + // Add Children to Node + for (uint i = 0; i < node->mNumChildren; i++) { + // this-> is necessary here otherwise + // it conflicts with the variable node + QEntity *child = this->node(node->mChildren[i]); + if (child != Q_NULLPTR) + entityNode->addChild(child); + } + + // Add Transformations + QTransform *transform = new QTransform(); + QMatrix4x4 qTransformMatrix = AssimpParser::aiMatrix4x4ToQMatrix4x4(node->mTransformation); + transform->setMatrix(qTransformMatrix); + entityNode->addComponent(transform); + + // Add Camera + if (m_cameras.contains(node)) + entityNode->addChild(m_cameras[node]); + + // TO DO : Add lights .... + + return entityNode; +} + +/*! + * Reads the scene file pointed by \a path and launches the parsing of + * the scene using Assimp after having cleaned up previously saved values + * from eventual previous parsings. + */ +void AssimpParser::readSceneFile(const QString &path) +{ + Assimp::Importer importer; + Assimp::DefaultLogger::create("AssimpLog.txt", Assimp::Logger::VERBOSE); + + // SET THIS TO REMOVE POINTS AND LINES -> HAVE ONLY TRIANGLES + importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE|aiPrimitiveType_POINT); + // SET CUSTOM FILE HANDLER TO HANDLE FILE READING THROUGH QT (RESOURCES, SOCKET ...) + importer.SetIOHandler(new AssimpHelper::AssimpIOSystem()); + + // type and aiProcess_Triangulate discompose polygons with more than 3 points in triangles + // aiProcess_SortByPType makes sur that meshes data are triangles + importer.ReadFile(path.toUtf8().constData(), + aiProcess_SortByPType| + aiProcess_Triangulate| + aiProcess_JoinIdenticalVertices| + aiProcess_GenSmoothNormals); + Assimp::DefaultLogger::kill(); + cleanup(); + aiScene *scene = Q_NULLPTR; + if (!(scene = importer.GetOrphanedScene())) { + qCWarning(AssimpParserLog) << "Assimp scene import failed"; + return ; + } + m_aiScene.reset(scene); + parse(); +} + +/*! + * Cleans the various dictionnaries holding the scenes infos. + */ +void AssimpParser::cleanup() +{ + m_meshes.clear(); + m_effects.clear(); + m_embeddedTextures.clear(); + m_materialTextures.clear(); + m_cameras.clear(); + m_sceneParsed = false; + if (!m_aiScene.isNull()) + m_aiScene.reset(0); +} + +/*! + * Parses the the aiScene provided py Assimp and convert Assimp + * values to Qt3D values. + */ +void AssimpParser::parse() +{ + if (!m_sceneParsed) { + // Set parsed flags + m_sceneParsed = !m_sceneParsed; + + for (uint i = 0; i < m_aiScene->mNumTextures; i++) + loadEmbeddedTexture(i); + for (uint i = 0; i < m_aiScene->mNumMaterials; i++) + loadMaterial(i); + for (uint i = 0; i < m_aiScene->mNumMeshes; i++) + loadMesh(i); + for (uint i = 0; i < m_aiScene->mNumCameras; i++) + loadCamera(i); + for (uint i = 0; i < m_aiScene->mNumLights; i++) + loadLight(i); + for (uint i = 0; i < m_aiScene->mNumAnimations; i++) + loadAnimation(i); + } +} + +/*! + * Converts the provided Assimp aiMaterial \a material to a Qt3D material. + * \sa Material and adds its to a dictionary of materials. + */ +void AssimpParser::loadMaterial(uint materialIndex) +{ + QMaterial *material = new QMaterial(); + aiMaterial *assimpMaterial = m_aiScene->mMaterials[materialIndex]; + // Material Name + copyMaterialName(material, assimpMaterial); + copyMaterialColorProperties(material, assimpMaterial); + copyMaterialBoolProperties(material, assimpMaterial); + copyMaterialFloatProperties(material, assimpMaterial); + + // Add textures to materials dict + copyMaterialTextures(material, assimpMaterial); + + // TO DO : Set Material Effect and Technique + + m_materials[materialIndex] = material; +} + +/*! + * Converts the Assimp aiMesh mesh identified by \a meshIndex to a QMeshData + * \sa QMeshData and adds it to a dictionary of meshes. + */ +void AssimpParser::loadMesh(uint meshIndex) +{ + aiMesh *mesh = m_aiScene->mMeshes[meshIndex]; + + // Primitive are always triangles with the current Assimp's configuration + QMeshDataPtr meshData(new QMeshData(GL_TRIANGLES)); + + // Mesh Name + QString meshName = QString::fromUtf8(mesh->mName.data); + + // Vertices and Normals always present with the current Assimp's configuration + aiVector3D *vertices = mesh->mVertices; + aiVector3D *normals = mesh->mNormals; + aiColor4D *colors = mesh->mColors[0]; + // Tangents and TextureCoord not always present + bool hasTangent = mesh->HasTangentsAndBitangents(); + bool hasTexture = mesh->HasTextureCoords(0); + bool hasColor = (colors != NULL); // NULL defined by Assimp + aiVector3D *tangents = hasTangent ? mesh->mTangents : Q_NULLPTR; + aiVector3D *textureCoord = hasTexture ? mesh->mTextureCoords[0] : Q_NULLPTR; + + // Add values in raw float array + ushort chunkSize = 6 + (hasTangent ? 3 : 0) + (hasTexture ? 2 : 0) + (hasColor ? 4 : 0); + QByteArray bufferArray; + bufferArray.resize(chunkSize * mesh->mNumVertices * sizeof(float)); + float *vbufferContent = reinterpret_cast<float*>(bufferArray.data()); + for (uint i = 0; i < mesh->mNumVertices; i++) { + uint idx = i * chunkSize; + // position + vbufferContent[idx] = vertices[i].x; + vbufferContent[idx + 1] = vertices[i].y; + vbufferContent[idx + 2] = vertices[i].z; + // normals + vbufferContent[idx + 3] = normals[i].x; + vbufferContent[idx + 4] = normals[i].y; + vbufferContent[idx + 5] = normals[i].z; + + if (hasTangent) { + vbufferContent[idx + 6] = tangents[i].x; + vbufferContent[idx + 7] = tangents[i].y; + vbufferContent[idx + 8] = tangents[i].z; + } + if (hasTexture) { + char offset = (hasTangent ? 9 : 6); + vbufferContent[idx + offset] = textureCoord[i].x; + vbufferContent[idx + offset + 1] = textureCoord[i].y; + } + if (hasColor) { + char offset = 6 + (hasTangent ? 3 : 0) + (hasTexture ? 2 : 0); + vbufferContent[idx + offset] = colors[i].r; + vbufferContent[idx + offset + 1] = colors[i].g; + vbufferContent[idx + offset + 2] = colors[i].b; + vbufferContent[idx + offset + 3] = colors[i].a; + } + } + // Create a Buffer from the raw array + BufferPtr vbuffer(new Buffer(QOpenGLBuffer::VertexBuffer)); + vbuffer->setUsage(QOpenGLBuffer::StaticDraw); + vbuffer->setData(bufferArray); + + // Add vertex attributes to the mesh with the right array + meshData->addAttribute(VERTICES_ATTRIBUTE_NAME, + AttributePtr(new Attribute(vbuffer, + GL_FLOAT_VEC3, + mesh->mNumVertices, + 0, + chunkSize * sizeof(float)))); + meshData->addAttribute(NORMAL_ATTRIBUTE_NAME, + AttributePtr(new Attribute(vbuffer, + GL_FLOAT_VEC3, + mesh->mNumVertices, + 3 * sizeof(float), + chunkSize * sizeof(float)))); + if (hasTangent) + meshData->addAttribute(TANGENT_ATTRIBUTE_NAME, + AttributePtr(new Attribute(vbuffer, + GL_FLOAT_VEC3, + mesh->mNumVertices, + 6 * sizeof(float), + chunkSize * sizeof(float)))); + if (hasTexture) + meshData->addAttribute(TEXTCOORD_ATTRIBUTE_NAME, + AttributePtr(new Attribute(vbuffer, + GL_FLOAT_VEC2, + mesh->mNumVertices, + (hasTangent ? 9 : 6) * sizeof(float), + chunkSize * sizeof(float)))); + if (hasColor) + meshData->addAttribute(COLOR_ATTRIBUTE_NAME, + AttributePtr(new Attribute(vbuffer, + GL_FLOAT_VEC4, + mesh->mNumVertices, + (6 + (hasTangent ? 3 : 0) + (hasTexture ? 2 : 0)) * sizeof(float), + chunkSize * sizeof(float)))); + GLuint indiceType; + QByteArray ibufferContent; + uint indices = mesh->mNumFaces * 3; + // If there are less than 65535 indices, indices can then fit in ushort + // which saves video memory + if (indices >= USHRT_MAX) { + indiceType = GL_UNSIGNED_INT; + ibufferContent.resize(indices * sizeof(quint32)); + for (uint i = 0; i < mesh->mNumFaces; i++) { + aiFace face = mesh->mFaces[i]; + Q_ASSERT(face.mNumIndices == 3); + memcpy(&reinterpret_cast<quint32*>(ibufferContent.data())[i * 3], face.mIndices, 3 * sizeof(uint)); + } + } + else { + indiceType = GL_UNSIGNED_SHORT; + ibufferContent.resize(indices * sizeof(quint16)); + for (uint i = 0; i < mesh->mNumFaces; i++) { + aiFace face = mesh->mFaces[i]; + Q_ASSERT(face.mNumIndices == 3); + for (ushort j = 0; j < face.mNumIndices; j++) + reinterpret_cast<quint16*>(ibufferContent.data())[i * 3 + j] = face.mIndices[j]; + } + } + + // Create Indices buffer + BufferPtr ibuffer(new Buffer(QOpenGLBuffer::IndexBuffer)); + ibuffer->setUsage(QOpenGLBuffer::StaticDraw); + ibuffer->setData(ibufferContent); + + // Add indices attributes + meshData->setIndexAttribute(AttributePtr(new Attribute(ibuffer, indiceType, indices, 0, 0))); + + meshData->computeBoundsFromAttribute(VERTICES_ATTRIBUTE_NAME); + + AssimpMesh *storedMesh = new AssimpMesh(); + storedMesh->setData(meshData); + m_meshes[meshIndex] = storedMesh; + + qCDebug(AssimpParserLog) << Q_FUNC_INFO << " Mesh " << meshName << " Vertices " << mesh->mNumVertices << " Faces " << mesh->mNumFaces << " Indices " << indices; +} + +/*! + * Converts the provided Assimp aiTexture at \a textureIndex to a Texture and + * adds it ot a dictionary of textures. + * \sa Texture + */ +void AssimpParser::loadEmbeddedTexture(uint textureIndex) +{ + aiTexture *assimpTexture = m_aiScene->mTextures[textureIndex]; + QTexture *texture = new QTexture(); + TexImageDataPtr textureData(new TexImageData(0, 0)); + + bool isCompressed = assimpTexture->mHeight == 0; + uint textureSize = assimpTexture->mWidth * + (isCompressed ? assimpTexture->mHeight : 1); + // Set texture to RGBA8888 + char *textureContent = new char[textureSize * 4]; + for (uint i = 0; i < textureSize; i++) { + uint idx = i * 4; + aiTexel texel = assimpTexture->pcData[i]; + textureContent[idx] = texel.r; + textureContent[idx + 1] = texel.g; + textureContent[idx + 2] = texel.b; + textureContent[idx + 3] = texel.a; + } + textureData->setData(QByteArray(textureContent, textureSize * 4), + QOpenGLTexture::RGBA, + QOpenGLTexture::UInt8); + texture->addImageData(textureData); + m_embeddedTextures[textureIndex] = texture; +} + +/*! + * Loads the light in the current scene located at \a lightIndex. + */ +void AssimpParser::loadLight(uint lightIndex) +{ + aiLight *light = m_aiScene->mLights[lightIndex]; + // TODO: Implement me! + Q_UNUSED(light); +} + +/*! + * Parses the camera at cameraIndex and saves it to a dictionary of cameras. + */ +void AssimpParser::loadCamera(uint cameraIndex) +{ + aiCamera *assimpCamera = m_aiScene->mCameras[cameraIndex]; + aiNode *cameraNode = m_aiScene->mRootNode->FindNode(assimpCamera->mName); + + // If no node is associated to the camera in the scene, camera not saved + if (cameraNode == Q_NULLPTR) + return ; + + QEntity *camera = new QEntity(); + QCameraLens *lens = new QCameraLens(); + aiMatrix4x4 cm; + + assimpCamera->GetCameraMatrix(cm); + lens->setObjectName(QString::fromUtf8(assimpCamera->mName.data)); + lens->setPerspectiveProjection(qRadiansToDegrees(assimpCamera->mHorizontalFOV), + qMax(assimpCamera->mAspect, 1.0f), + assimpCamera->mClipPlaneNear, + assimpCamera->mClipPlaneFar); + camera->addComponent(lens); + // View Matrix defines camera position & up vector relative to the associated + // node in the scene. This is computed in AssimpParser::node + // camera->lookAt()->setViewMatrix(); + QTransform *transform = new QTransform(); + QMatrix4x4 viewMatrix = AssimpParser::aiMatrix4x4ToQMatrix4x4(cm); + // CHECK THAT THIS WORKS + qCDebug(AssimpParserLog) << Q_FUNC_INFO << "IF CAMERA NOT BEHAVING CORRECTLY LOOK HERE"; + viewMatrix.lookAt(QVector3D(0, 0, 0), + QVector3D(assimpCamera->mLookAt.x, assimpCamera->mLookAt.y, assimpCamera->mLookAt.z), + QVector3D(0, 0, 0)); + transform->setMatrix(viewMatrix); + camera->addComponent(transform); + m_cameras[cameraNode] = camera; +} + +// OPTIONAL +void AssimpParser::loadAnimation(uint animationIndex) +{ + Q_UNUSED(animationIndex) +} + +/*! + * Sets the object name of \a material to the name of \a assimpMaterial. + */ +void AssimpParser::copyMaterialName(QMaterial *material, aiMaterial *assimpMaterial) +{ + aiString name; + if (assimpMaterial->Get(AI_MATKEY_NAME, name) == aiReturn_SUCCESS) { + // May not be necessary + // Kept for debug purposes at the moment + material->setObjectName(QString::fromUtf8(name.data)); + qCDebug(AssimpParserLog) << Q_FUNC_INFO << "Assimp Material " << material->objectName(); + } +} + +/*! + * Fills \a material color properties with \a assimpMaterial color properties; + */ +void AssimpParser::copyMaterialColorProperties(QMaterial *material, aiMaterial *assimpMaterial) +{ + aiColor3D color; + if (assimpMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_DIFFUSE_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + if (assimpMaterial->Get(AI_MATKEY_COLOR_SPECULAR, color) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_SPECULAR_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + if (assimpMaterial->Get(AI_MATKEY_COLOR_AMBIENT, color) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_AMBIENT_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + if (assimpMaterial->Get(AI_MATKEY_COLOR_EMISSIVE, color) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_EMISSIVE_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + if (assimpMaterial->Get(AI_MATKEY_COLOR_TRANSPARENT, color) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_TRANSPARENT_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); + if (assimpMaterial->Get(AI_MATKEY_COLOR_REFLECTIVE, color) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_REFLECTIVE_COLOR, QColor::fromRgbF(color.r, color.g, color.b))); +} + +/*! + * Retrieves a\a material bool property; + */ +void AssimpParser::copyMaterialBoolProperties(QMaterial *material, aiMaterial *assimpMaterial) +{ + int value; + if (assimpMaterial->Get(AI_MATKEY_TWOSIDED, value) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_IS_TWOSIDED, (value == 0) ? false : true)); + if (assimpMaterial->Get(AI_MATKEY_ENABLE_WIREFRAME, value) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_IS_WIREFRAME, (value == 0) ? false : true)); +} + +void AssimpParser::copyMaterialShadingModel(QMaterial *material, aiMaterial *assimpMaterial) +{ + Q_UNUSED(material) + Q_UNUSED(assimpMaterial) + // TODO + // Match each shading function with a default shader + + // AssimpParser::assimpMaterialAttributesMap[AI_MATKEY_SHADING_MODEL] = &AssimpParser::getMaterialShadingModel; + // AssimpParser::assimpMaterialAttributesMap[AI_MATKEY_BLEND_FUNC] = &AssimpParser::getMaterialBlendingFunction; +} + +void AssimpParser::copyMaterialBlendingFunction(QMaterial *material, aiMaterial *assimpMaterial) +{ + Q_UNUSED(material) + Q_UNUSED(assimpMaterial) + // TO DO +} + +/*! + * + */ +void AssimpParser::copyMaterialTextures(QMaterial *material, aiMaterial *assimpMaterial) +{ + static const aiTextureType textureType[] = {aiTextureType_AMBIENT, + aiTextureType_DIFFUSE, + aiTextureType_DISPLACEMENT, + aiTextureType_EMISSIVE, + aiTextureType_HEIGHT, + aiTextureType_LIGHTMAP, + aiTextureType_NORMALS, + aiTextureType_OPACITY, + aiTextureType_REFLECTION, + aiTextureType_SHININESS, + aiTextureType_SPECULAR, + /*aiTextureType_UNKNOWN*/}; + + if (m_textureToParameterName.isEmpty()) { + m_textureToParameterName[aiTextureType_AMBIENT] = ASSIMP_MATERIAL_AMBIENT_TEXTURE; + m_textureToParameterName[aiTextureType_DIFFUSE] = ASSIMP_MATERIAL_DIFFUSE_TEXTURE; + m_textureToParameterName[aiTextureType_DISPLACEMENT] = ASSIMP_MATERIAL_DISPLACEMENT_TEXTURE; + m_textureToParameterName[aiTextureType_EMISSIVE] = ASSIMP_MATERIAL_EMISSIVE_TEXTURE; + m_textureToParameterName[aiTextureType_HEIGHT] = ASSIMP_MATERIAL_HEIGHT_TEXTURE; + m_textureToParameterName[aiTextureType_LIGHTMAP] = ASSIMP_MATERIAL_LIGHTMAP_TEXTURE; + m_textureToParameterName[aiTextureType_NORMALS] = ASSIMP_MATERIAL_NORMALS_TEXTURE; + m_textureToParameterName[aiTextureType_OPACITY] = ASSIMP_MATERIAL_OPACITY_TEXTURE; + m_textureToParameterName[aiTextureType_REFLECTION] = ASSIMP_MATERIAL_REFLECTION_TEXTURE; + m_textureToParameterName[aiTextureType_SHININESS] = ASSIMP_MATERIAL_SHININESS_TEXTURE; + m_textureToParameterName[aiTextureType_SPECULAR] = ASSIMP_MATERIAL_SPECULAR_TEXTURE; + } + + for (unsigned int i = 0; i < sizeof(textureType)/sizeof(textureType[0]); i++) { + aiString path; + if (assimpMaterial->GetTexture(textureType[i], 0, &path) == AI_SUCCESS) { + QString fullPath = m_sceneDir.absoluteFilePath(QString::fromUtf8(path.data)); + // Load texture if not already loaded + bool textureLoaded = true; + if (!m_materialTextures.contains(fullPath)) { + QTexture *tex = new QTexture(); + QImage textureImage; + if (!textureImage.load(fullPath) || !textureImage.isNull()) { + tex->setFromQImage(textureImage); + m_materialTextures[fullPath] = tex; + qCWarning(AssimpParserLog) << Q_FUNC_INFO << " Loaded Texture " << fullPath; + } + else { + qCWarning(AssimpParserLog) << Q_FUNC_INFO << " Invalid Texture " << fullPath; + textureLoaded = false; + } + } + if (textureLoaded) { + material->addParameter(new QParameter(material, m_textureToParameterName[textureType[i]], + QVariant::fromValue(m_materialTextures[fullPath]))); + } + } + } +} + +/*! + * Retrieves a\a material float property. + */ +void AssimpParser::copyMaterialFloatProperties(QMaterial *material, aiMaterial *assimpMaterial) +{ + float value = 0; + if (assimpMaterial->Get(AI_MATKEY_OPACITY, value) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_OPACITY, value)); + if (assimpMaterial->Get(AI_MATKEY_SHININESS, value) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_SHININESS,value)); + if (assimpMaterial->Get(AI_MATKEY_SHININESS_STRENGTH, value) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_SHININESS_STRENGTH, value)); + if (assimpMaterial->Get(AI_MATKEY_REFRACTI, value) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_REFRACTI, value)); + if (assimpMaterial->Get(AI_MATKEY_REFLECTIVITY, value) == aiReturn_SUCCESS) + material->addParameter(new QParameter(material, ASSIMP_MATERIAL_REFLECTIVITY, value)); +} + +AssimpMesh::AssimpMesh(QNode *parent) + : QAbstractMesh(parent) +{ +} + +void AssimpMesh::copy(const QNode *ref) +{ + QAbstractMesh::copy(ref); + const AssimpMesh *mesh = qobject_cast<const AssimpMesh *>(ref); + if (mesh != Q_NULLPTR) { + m_meshData = mesh->m_meshData; + } +} + +void AssimpMesh::setData(QMeshDataPtr data) +{ + m_meshData = data; + QAbstractMesh::setDirty(this); +} + +AssimpMesh *AssimpMesh::doClone(QNode *clonedParent) const +{ + return new AssimpMesh(clonedParent); +} + +QAbstractMeshFunctorPtr AssimpMesh::meshFunctor() const +{ + return QAbstractMeshFunctorPtr(new AssimpMeshFunctor(m_meshData)); +} + +AssimpMesh::AssimpMeshFunctor::AssimpMeshFunctor(QMeshDataPtr meshData) + : QAbstractMeshFunctor() + , m_meshData(meshData) +{ +} + +QAbstractMeshDataPtr AssimpMesh::AssimpMeshFunctor::operator()() +{ + return m_meshData; +} + +} // Qt3D + +QT_END_NAMESPACE + +#include "assimpparser.moc" diff --git a/src/plugins/sceneparsers/assimp/assimpparser_p.h b/src/plugins/sceneparsers/assimp/assimpparser_p.h new file mode 100644 index 000000000..1f6f14748 --- /dev/null +++ b/src/plugins/sceneparsers/assimp/assimpparser_p.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 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 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_ASSIMPPARSER_H +#define QT3D_ASSIMPPARSER_H + +// ASSIMP LIBRARY INCLUDE +#include <assimp/Importer.hpp> +#include <assimp/scene.h> +#include <assimp/postprocess.h> +#include <assimp/DefaultLogger.hpp> +#include <Qt3DCore/qabstractmesh.h> +#include <Qt3DRenderer/qmeshdata.h> +#include <Qt3DRenderer/private/abstractsceneparser_p.h> +#include "assimphelpers_p.h" + +#include <QMap> +#include <QDir> +#include <QLoggingCategory> + +QT_BEGIN_NAMESPACE + +class QFile; + +namespace Qt3D { + +class QMaterial; +class QShaderProgram; +class QEffect; +class QCamera; +class QTexture; +class QMesh; +class AssimpMesh; + +Q_DECLARE_LOGGING_CATEGORY(AssimpParserLog) + +class AssimpParser : public AbstractSceneParser +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt3DRenderer.AssimParser") +public: + AssimpParser(); + ~AssimpParser(); + + static bool isAssimpPath(const QString& path); + + // SceneParserInterface interface + void setFilePath(const QString& path) Q_DECL_OVERRIDE; + bool isPathExtensionSupported(const QString &path) Q_DECL_OVERRIDE; + QEntity *scene(QString id = QString()) Q_DECL_OVERRIDE; + QEntity *node(QString id) Q_DECL_OVERRIDE; + + QEntity *defaultScene(); + QMeshDataPtr mesh(QString id); + QMaterial *material(QString id); + QCamera *camera(QString id); + +private : + + static QStringList assimpSupportedFormats(); + static QMatrix4x4 aiMatrix4x4ToQMatrix4x4(const aiMatrix4x4 &matrix); + + QEntity *node(aiNode *node); + + void readSceneFile(const QString &file); + + void cleanup(); + void parse(); + + void loadMaterial(uint materialIndex); + void loadMesh(uint meshIndex); + void loadEmbeddedTexture(uint textureIndex); + void loadLight(uint lightIndex); + void loadCamera(uint cameraIndex); + void loadAnimation(uint animationIndex); + + void copyMaterialName(QMaterial *material, aiMaterial *assimpMaterial); + void copyMaterialColorProperties(QMaterial *material, aiMaterial *assimpMaterial); + void copyMaterialFloatProperties(QMaterial *material, aiMaterial *assimpMaterial); + void copyMaterialBoolProperties(QMaterial *material, aiMaterial *assimpMaterial); + void copyMaterialShadingModel(QMaterial *material, aiMaterial *assimpMaterial); + void copyMaterialBlendingFunction(QMaterial *material, aiMaterial *assimpMaterial); + void copyMaterialTextures(QMaterial *material, aiMaterial *assimpMaterial); + + QScopedPointer<aiScene> m_aiScene; + QDir m_sceneDir; + bool m_sceneParsed; + static QStringList assimpSupportedFormatsList; + + QMap<uint, AssimpMesh *> m_meshes; + QMap<uint, QMaterial*> m_materials; + QMap<uint, QEffect *> m_effects; + QMap<uint, QTexture*> m_embeddedTextures; + QMap<QString, QTexture*> m_materialTextures; + QMap<aiNode*, QEntity*> m_cameras; + + QHash<aiTextureType, QString> m_textureToParameterName; + +// QMap<aiNode*, Light*> m_lights; + +}; + +} + +QT_END_NAMESPACE + +#endif // QT3D_ASSIMPPARSER_H diff --git a/src/plugins/sceneparsers/sceneparsers.pro b/src/plugins/sceneparsers/sceneparsers.pro new file mode 100644 index 000000000..90a15ede2 --- /dev/null +++ b/src/plugins/sceneparsers/sceneparsers.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +config_assimp { + SUBDIRS += assimp +} |