summaryrefslogtreecommitdiffstats
path: root/src/plugins/sceneparsers/assimp/assimpparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/sceneparsers/assimp/assimpparser.cpp')
-rw-r--r--src/plugins/sceneparsers/assimp/assimpparser.cpp862
1 files changed, 862 insertions, 0 deletions
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"