From 3cd55c54dbf66a320438d743fbd223952043cd39 Mon Sep 17 00:00:00 2001 From: Andy Maloney Date: Wed, 7 Dec 2016 19:33:08 -0500 Subject: Update assimp lib to 3.3.1 The currently included assimp lib is v3.0 from 2012. This updates assimp lib to the latest released version (3.3.1). Change-Id: I15a60e3150c0b268422f23137107b34e4c5c4342 Reviewed-by: Sean Harmer --- src/3rdparty/assimp/code/ObjFileImporter.cpp | 1198 ++++++++++++++------------ 1 file changed, 629 insertions(+), 569 deletions(-) (limited to 'src/3rdparty/assimp/code/ObjFileImporter.cpp') diff --git a/src/3rdparty/assimp/code/ObjFileImporter.cpp b/src/3rdparty/assimp/code/ObjFileImporter.cpp index af0038a31..082709dc7 100644 --- a/src/3rdparty/assimp/code/ObjFileImporter.cpp +++ b/src/3rdparty/assimp/code/ObjFileImporter.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -25,674 +25,734 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER #include "DefaultIOSystem.h" #include "ObjFileImporter.h" #include "ObjFileParser.h" #include "ObjFileData.h" +#include +#include +#include +#include +#include + static const aiImporterDesc desc = { - "Wavefront Object Importer", - "", - "", - "surfaces not supported", - aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "obj" + "Wavefront Object Importer", + "", + "", + "surfaces not supported", + aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "obj" }; static const unsigned int ObjMinSize = 16; -namespace Assimp { +namespace Assimp { using namespace std; // ------------------------------------------------------------------------------------------------ -// Default constructor +// Default constructor ObjFileImporter::ObjFileImporter() : - m_Buffer(), - m_pRootObject( NULL ), - m_strAbsPath( "" ) + m_Buffer(), + m_pRootObject( NULL ), + m_strAbsPath( "" ) { DefaultIOSystem io; - m_strAbsPath = io.getOsSeparator(); + m_strAbsPath = io.getOsSeparator(); } // ------------------------------------------------------------------------------------------------ -// Destructor. +// Destructor. ObjFileImporter::~ObjFileImporter() { - delete m_pRootObject; - m_pRootObject = NULL; + delete m_pRootObject; + m_pRootObject = NULL; } // ------------------------------------------------------------------------------------------------ -// Returns true, if file is an obj file. +// Returns true, if file is an obj file. bool ObjFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler , bool checkSig ) const { - if(!checkSig) //Check File Extension - { - return SimpleExtensionCheck(pFile,"obj"); - } - else //Check file Header - { - static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " }; - return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9 ); - } + if(!checkSig) //Check File Extension + { + return SimpleExtensionCheck(pFile,"obj"); + } + else //Check file Header + { + static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " }; + return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9 ); + } } // ------------------------------------------------------------------------------------------------ const aiImporterDesc* ObjFileImporter::GetInfo () const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ -// Obj-file import implementation -void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) -{ - DefaultIOSystem io; - - // Read file into memory - const std::string mode = "rb"; - boost::scoped_ptr file( pIOHandler->Open( pFile, mode)); - if( !file.get() ) { - throw DeadlyImportError( "Failed to open file " + pFile + "." ); +// Obj-file import implementation +void ObjFileImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSystem* pIOHandler) { + // Read file into memory + static const std::string mode = "rb"; + std::unique_ptr fileStream( pIOHandler->Open( file, mode)); + if( !fileStream.get() ) { + throw DeadlyImportError( "Failed to open file " + file + "." ); } - // Get the file-size and validate it, throwing an exception when fails - size_t fileSize = file->FileSize(); + // Get the file-size and validate it, throwing an exception when fails + size_t fileSize = fileStream->FileSize(); if( fileSize < ObjMinSize ) { - throw DeadlyImportError( "OBJ-file is too small."); + throw DeadlyImportError( "OBJ-file is too small."); + } + + // Allocate buffer and read file into it + TextFileToBuffer( fileStream.get(),m_Buffer); + + // Get the model name + std::string modelName, folderName; + std::string::size_type pos = file.find_last_of( "\\/" ); + if ( pos != std::string::npos ) { + modelName = file.substr(pos+1, file.size() - pos - 1); + folderName = file.substr( 0, pos ); + if ( !folderName.empty() ) { + pIOHandler->PushDirectory( folderName ); + } + } else { + modelName = file; + } + + // This next stage takes ~ 1/3th of the total readFile task + // so should amount for 1/3th of the progress + // only update every 100KB or it'll be too slow + unsigned int progress = 0; + unsigned int progressCounter = 0; + const unsigned int updateProgressEveryBytes = 100 * 1024; + const unsigned int progressTotal = (3*m_Buffer.size()/updateProgressEveryBytes); + // process all '\' + std::vector ::iterator iter = m_Buffer.begin(); + while (iter != m_Buffer.end()) + { + if (*iter == '\\') + { + // remove '\' + iter = m_Buffer.erase(iter); + // remove next character + while (*iter == '\r' || *iter == '\n') + iter = m_Buffer.erase(iter); + } + else + ++iter; + + if (++progressCounter >= updateProgressEveryBytes) + { + m_progress->UpdateFileRead(++progress, progressTotal); + progressCounter = 0; + } } - // Allocate buffer and read file into it - TextFileToBuffer(file.get(),m_Buffer); - - // Get the model name - std::string strModelName; - std::string::size_type pos = pFile.find_last_of( "\\/" ); - if ( pos != std::string::npos ) - { - strModelName = pFile.substr(pos+1, pFile.size() - pos - 1); - } - else - { - strModelName = pFile; - } - - // process all '\' - std::vector ::iterator iter = m_Buffer.begin(); - while (iter != m_Buffer.end()) - { - if (*iter == '\\') - { - // remove '\' - iter = m_Buffer.erase(iter); - // remove next character - while (*iter == '\r' || *iter == '\n') - iter = m_Buffer.erase(iter); - } - else - ++iter; - } - - // parse the file into a temporary representation - ObjFileParser parser(m_Buffer, strModelName, pIOHandler); - - // And create the proper return structures out of it - CreateDataFromImport(parser.GetModel(), pScene); - - // Clean up allocated storage for the next import - m_Buffer.clear(); + // 1/3rd progress + m_progress->UpdateFileRead(1, 3); + + // parse the file into a temporary representation + ObjFileParser parser(m_Buffer, modelName, pIOHandler, m_progress, file); + + // And create the proper return structures out of it + CreateDataFromImport(parser.GetModel(), pScene); + + // Clean up allocated storage for the next import + m_Buffer.clear(); + + // Pop directory stack + if ( pIOHandler->StackSize() > 0 ) { + pIOHandler->PopDirectory(); + } } // ------------------------------------------------------------------------------------------------ -// Create the data from parsed obj-file +// Create the data from parsed obj-file void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene* pScene) { if( 0L == pModel ) { return; } - - // Create the root node of the scene - pScene->mRootNode = new aiNode; - if ( !pModel->m_ModelName.empty() ) - { - // Set the name of the scene - pScene->mRootNode->mName.Set(pModel->m_ModelName); - } - else - { - // This is a fatal error, so break down the application - ai_assert(false); - } - - // Create nodes for the whole scene - std::vector MeshArray; - for (size_t index = 0; index < pModel->m_Objects.size(); index++) - { - createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray); - } - - // Create mesh pointer buffer for this scene - if (pScene->mNumMeshes > 0) - { - pScene->mMeshes = new aiMesh*[ MeshArray.size() ]; - for (size_t index =0; index < MeshArray.size(); index++) - { - pScene->mMeshes [ index ] = MeshArray[ index ]; - } - } - - // Create all materials - createMaterials( pModel, pScene ); + + // Create the root node of the scene + pScene->mRootNode = new aiNode; + if ( !pModel->m_ModelName.empty() ) + { + // Set the name of the scene + pScene->mRootNode->mName.Set(pModel->m_ModelName); + } + else + { + // This is a fatal error, so break down the application + ai_assert(false); + } + + // Create nodes for the whole scene + std::vector MeshArray; + for (size_t index = 0; index < pModel->m_Objects.size(); index++) + { + createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray); + } + + // Create mesh pointer buffer for this scene + if (pScene->mNumMeshes > 0) + { + pScene->mMeshes = new aiMesh*[ MeshArray.size() ]; + for (size_t index =0; index < MeshArray.size(); index++) + { + pScene->mMeshes[ index ] = MeshArray[ index ]; + } + } + + // Create all materials + createMaterials( pModel, pScene ); } // ------------------------------------------------------------------------------------------------ -// Creates all nodes of the model -aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pObject, - aiNode *pParent, aiScene* pScene, - std::vector &MeshArray ) +// Creates all nodes of the model +aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pObject, + aiNode *pParent, aiScene* pScene, + std::vector &MeshArray ) { - ai_assert( NULL != pModel ); + ai_assert( NULL != pModel ); if( NULL == pObject ) { return NULL; } - - // Store older mesh size to be able to computes mesh offsets for new mesh instances - const size_t oldMeshSize = MeshArray.size(); - aiNode *pNode = new aiNode; - - pNode->mName = pObject->m_strObjName; - - // If we have a parent node, store it + + // Store older mesh size to be able to computes mesh offsets for new mesh instances + const size_t oldMeshSize = MeshArray.size(); + aiNode *pNode = new aiNode; + + pNode->mName = pObject->m_strObjName; + + // If we have a parent node, store it if( pParent != NULL ) { appendChildToParentNode( pParent, pNode ); } - for ( unsigned int i=0; i< pObject->m_Meshes.size(); i++ ) - { - unsigned int meshId = pObject->m_Meshes[ i ]; - aiMesh *pMesh = new aiMesh; - createTopology( pModel, pObject, meshId, pMesh ); - if ( pMesh->mNumVertices > 0 ) - { - MeshArray.push_back( pMesh ); - } - else - { - delete pMesh; - } - } - - // Create all nodes from the sub-objects stored in the current object - if ( !pObject->m_SubObjects.empty() ) - { - size_t numChilds = pObject->m_SubObjects.size(); - pNode->mNumChildren = static_cast( numChilds ); - pNode->mChildren = new aiNode*[ numChilds ]; - pNode->mNumMeshes = 1; - pNode->mMeshes = new unsigned int[ 1 ]; - } - - // Set mesh instances into scene- and node-instances - const size_t meshSizeDiff = MeshArray.size()- oldMeshSize; - if ( meshSizeDiff > 0 ) - { - pNode->mMeshes = new unsigned int[ meshSizeDiff ]; - pNode->mNumMeshes = static_cast( meshSizeDiff ); - size_t index = 0; - for (size_t i = oldMeshSize; i < MeshArray.size(); i++) - { - pNode->mMeshes[ index ] = pScene->mNumMeshes; - pScene->mNumMeshes++; - index++; - } - } - - return pNode; + for ( size_t i=0; i< pObject->m_Meshes.size(); i++ ) + { + unsigned int meshId = pObject->m_Meshes[ i ]; + aiMesh *pMesh = createTopology( pModel, pObject, meshId ); + if( pMesh && pMesh->mNumFaces > 0 ) { + MeshArray.push_back( pMesh ); + } + } + + // Create all nodes from the sub-objects stored in the current object + if ( !pObject->m_SubObjects.empty() ) + { + size_t numChilds = pObject->m_SubObjects.size(); + pNode->mNumChildren = static_cast( numChilds ); + pNode->mChildren = new aiNode*[ numChilds ]; + pNode->mNumMeshes = 1; + pNode->mMeshes = new unsigned int[ 1 ]; + } + + // Set mesh instances into scene- and node-instances + const size_t meshSizeDiff = MeshArray.size()- oldMeshSize; + if ( meshSizeDiff > 0 ) + { + pNode->mMeshes = new unsigned int[ meshSizeDiff ]; + pNode->mNumMeshes = static_cast( meshSizeDiff ); + size_t index = 0; + for (size_t i = oldMeshSize; i < MeshArray.size(); i++) + { + pNode->mMeshes[ index ] = pScene->mNumMeshes; + pScene->mNumMeshes++; + index++; + } + } + + return pNode; } // ------------------------------------------------------------------------------------------------ -// Create topology data -void ObjFileImporter::createTopology(const ObjFile::Model* pModel, - const ObjFile::Object* pData, - unsigned int uiMeshIndex, - aiMesh* pMesh ) +// Create topology data +aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const ObjFile::Object* pData, + unsigned int meshIndex ) { - // Checking preconditions - ai_assert( NULL != pModel ); + // Checking preconditions + ai_assert( NULL != pModel ); + if( NULL == pData ) { - return; + return NULL; } - // Create faces - ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ]; - ai_assert( NULL != pObjMesh ); - - pMesh->mNumFaces = 0; - for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) - { - ObjFile::Face* const inp = pObjMesh->m_Faces[ index ]; - - if (inp->m_PrimitiveType == aiPrimitiveType_LINE) { - pMesh->mNumFaces += inp->m_pVertices->size() - 1; - pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - } - else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) { - pMesh->mNumFaces += inp->m_pVertices->size(); - pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - } else { - ++pMesh->mNumFaces; - if (inp->m_pVertices->size() > 3) { - pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - } - else { - pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - } - } - } - - unsigned int uiIdxCount = 0u; - if ( pMesh->mNumFaces > 0 ) - { - pMesh->mFaces = new aiFace[ pMesh->mNumFaces ]; - if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial ) - { - pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex; - } - - unsigned int outIndex = 0; - - // Copy all data from all stored meshes - for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) - { - ObjFile::Face* const inp = pObjMesh->m_Faces[ index ]; - if (inp->m_PrimitiveType == aiPrimitiveType_LINE) { - for(size_t i = 0; i < inp->m_pVertices->size() - 1; ++i) { - aiFace& f = pMesh->mFaces[ outIndex++ ]; - uiIdxCount += f.mNumIndices = 2; - f.mIndices = new unsigned int[2]; - } - continue; - } - else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) { - for(size_t i = 0; i < inp->m_pVertices->size(); ++i) { - aiFace& f = pMesh->mFaces[ outIndex++ ]; - uiIdxCount += f.mNumIndices = 1; - f.mIndices = new unsigned int[1]; - } - continue; - } - - aiFace *pFace = &pMesh->mFaces[ outIndex++ ]; - const unsigned int uiNumIndices = (unsigned int) pObjMesh->m_Faces[ index ]->m_pVertices->size(); - uiIdxCount += pFace->mNumIndices = (unsigned int) uiNumIndices; - if (pFace->mNumIndices > 0) { - pFace->mIndices = new unsigned int[ uiNumIndices ]; - } - } - } - - // Create mesh vertices - createVertexArray(pModel, pData, uiMeshIndex, pMesh, uiIdxCount); + // Create faces + ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ meshIndex ]; + if( !pObjMesh ) { + return NULL; + } + + if( pObjMesh->m_Faces.empty() ) { + return NULL; + } + + aiMesh* pMesh = new aiMesh; + if( !pObjMesh->m_name.empty() ) { + pMesh->mName.Set( pObjMesh->m_name ); + } + + for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) + { + ObjFile::Face *const inp = pObjMesh->m_Faces[ index ]; + ai_assert( NULL != inp ); + + if (inp->m_PrimitiveType == aiPrimitiveType_LINE) { + pMesh->mNumFaces += inp->m_pVertices->size() - 1; + pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + } else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) { + pMesh->mNumFaces += inp->m_pVertices->size(); + pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT; + } else { + ++pMesh->mNumFaces; + if (inp->m_pVertices->size() > 3) { + pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; + } else { + pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + } + } + } + + unsigned int uiIdxCount( 0u ); + if ( pMesh->mNumFaces > 0 ) { + pMesh->mFaces = new aiFace[ pMesh->mNumFaces ]; + if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial ) { + pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex; + } + + unsigned int outIndex( 0 ); + + // Copy all data from all stored meshes + for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) { + ObjFile::Face* const inp = pObjMesh->m_Faces[ index ]; + if (inp->m_PrimitiveType == aiPrimitiveType_LINE) { + for(size_t i = 0; i < inp->m_pVertices->size() - 1; ++i) { + aiFace& f = pMesh->mFaces[ outIndex++ ]; + uiIdxCount += f.mNumIndices = 2; + f.mIndices = new unsigned int[2]; + } + continue; + } + else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) { + for(size_t i = 0; i < inp->m_pVertices->size(); ++i) { + aiFace& f = pMesh->mFaces[ outIndex++ ]; + uiIdxCount += f.mNumIndices = 1; + f.mIndices = new unsigned int[1]; + } + continue; + } + + aiFace *pFace = &pMesh->mFaces[ outIndex++ ]; + const unsigned int uiNumIndices = (unsigned int) pObjMesh->m_Faces[ index ]->m_pVertices->size(); + uiIdxCount += pFace->mNumIndices = (unsigned int) uiNumIndices; + if (pFace->mNumIndices > 0) { + pFace->mIndices = new unsigned int[ uiNumIndices ]; + } + } + } + + // Create mesh vertices + createVertexArray(pModel, pData, meshIndex, pMesh, uiIdxCount); + + return pMesh; } // ------------------------------------------------------------------------------------------------ -// Creates a vertex array -void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel, - const ObjFile::Object* pCurrentObject, - unsigned int uiMeshIndex, - aiMesh* pMesh, - unsigned int uiIdxCount) +// Creates a vertex array +void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel, + const ObjFile::Object* pCurrentObject, + unsigned int uiMeshIndex, + aiMesh* pMesh, + unsigned int numIndices) { - // Checking preconditions - ai_assert( NULL != pCurrentObject ); - - // Break, if no faces are stored in object - if ( pCurrentObject->m_Meshes.empty() ) - return; - - // Get current mesh - ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ]; - if ( NULL == pObjMesh || pObjMesh->m_uiNumIndices < 1) - return; - - // Copy vertices of this mesh instance - pMesh->mNumVertices = uiIdxCount; - pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ]; - - // Allocate buffer for normal vectors - if ( !pModel->m_Normals.empty() && pObjMesh->m_hasNormals ) - pMesh->mNormals = new aiVector3D[ pMesh->mNumVertices ]; - - // Allocate buffer for texture coordinates - if ( !pModel->m_TextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0] ) - { - pMesh->mNumUVComponents[ 0 ] = 2; - pMesh->mTextureCoords[ 0 ] = new aiVector3D[ pMesh->mNumVertices ]; - } - - // Copy vertices, normals and textures into aiMesh instance - unsigned int newIndex = 0, outIndex = 0; - for ( size_t index=0; index < pObjMesh->m_Faces.size(); index++ ) - { - // Get source face - ObjFile::Face *pSourceFace = pObjMesh->m_Faces[ index ]; - - // Copy all index arrays - for ( size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < pSourceFace->m_pVertices->size(); vertexIndex++ ) - { - const unsigned int vertex = pSourceFace->m_pVertices->at( vertexIndex ); - if ( vertex >= pModel->m_Vertices.size() ) - throw DeadlyImportError( "OBJ: vertex index out of range" ); - - pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ]; - - // Copy all normals - if ( !pModel->m_Normals.empty() && vertexIndex < pSourceFace->m_pNormals->size()) - { - const unsigned int normal = pSourceFace->m_pNormals->at( vertexIndex ); - if ( normal >= pModel->m_Normals.size() ) - throw DeadlyImportError("OBJ: vertex normal index out of range"); - - pMesh->mNormals[ newIndex ] = pModel->m_Normals[ normal ]; - } - - // Copy all texture coordinates - if ( !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_pTexturCoords->size()) - { - const unsigned int tex = pSourceFace->m_pTexturCoords->at( vertexIndex ); - ai_assert( tex < pModel->m_TextureCoord.size() ); - - if ( tex >= pModel->m_TextureCoord.size() ) - throw DeadlyImportError("OBJ: texture coordinate index out of range"); - - const aiVector3D &coord3d = pModel->m_TextureCoord[ tex ]; + // Checking preconditions + ai_assert( NULL != pCurrentObject ); + + // Break, if no faces are stored in object + if ( pCurrentObject->m_Meshes.empty() ) + return; + + // Get current mesh + ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ]; + if ( NULL == pObjMesh || pObjMesh->m_uiNumIndices < 1) + return; + + // Copy vertices of this mesh instance + pMesh->mNumVertices = numIndices; + if (pMesh->mNumVertices == 0) { + throw DeadlyImportError( "OBJ: no vertices" ); + } else if (pMesh->mNumVertices > AI_MAX_ALLOC(aiVector3D)) { + throw DeadlyImportError( "OBJ: Too many vertices, would run out of memory" ); + } + pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ]; + + // Allocate buffer for normal vectors + if ( !pModel->m_Normals.empty() && pObjMesh->m_hasNormals ) + pMesh->mNormals = new aiVector3D[ pMesh->mNumVertices ]; + + // Allocate buffer for vertex-color vectors + if ( !pModel->m_VertexColors.empty() ) + pMesh->mColors[0] = new aiColor4D[ pMesh->mNumVertices ]; + + // Allocate buffer for texture coordinates + if ( !pModel->m_TextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0] ) + { + pMesh->mNumUVComponents[ 0 ] = 2; + pMesh->mTextureCoords[ 0 ] = new aiVector3D[ pMesh->mNumVertices ]; + } + + // Copy vertices, normals and textures into aiMesh instance + unsigned int newIndex = 0, outIndex = 0; + for ( size_t index=0; index < pObjMesh->m_Faces.size(); index++ ) + { + // Get source face + ObjFile::Face *pSourceFace = pObjMesh->m_Faces[ index ]; + + // Copy all index arrays + for ( size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < pSourceFace->m_pVertices->size(); vertexIndex++ ) + { + const unsigned int vertex = pSourceFace->m_pVertices->at( vertexIndex ); + if ( vertex >= pModel->m_Vertices.size() ) + throw DeadlyImportError( "OBJ: vertex index out of range" ); + + pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ]; + + // Copy all normals + if ( !pModel->m_Normals.empty() && vertexIndex < pSourceFace->m_pNormals->size()) + { + const unsigned int normal = pSourceFace->m_pNormals->at( vertexIndex ); + if ( normal >= pModel->m_Normals.size() ) + throw DeadlyImportError("OBJ: vertex normal index out of range"); + + pMesh->mNormals[ newIndex ] = pModel->m_Normals[ normal ]; + } + + // Copy all vertex colors + if ( !pModel->m_VertexColors.empty()) + { + const aiVector3D color = pModel->m_VertexColors[ vertex ]; + pMesh->mColors[0][ newIndex ] = aiColor4D(color.x, color.y, color.z, 1.0); + } + + // Copy all texture coordinates + if ( !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_pTexturCoords->size()) + { + const unsigned int tex = pSourceFace->m_pTexturCoords->at( vertexIndex ); + ai_assert( tex < pModel->m_TextureCoord.size() ); + + if ( tex >= pModel->m_TextureCoord.size() ) + throw DeadlyImportError("OBJ: texture coordinate index out of range"); + + const aiVector3D &coord3d = pModel->m_TextureCoord[ tex ]; pMesh->mTextureCoords[ 0 ][ newIndex ] = aiVector3D( coord3d.x, coord3d.y, coord3d.z ); - } - - ai_assert( pMesh->mNumVertices > newIndex ); - - // Get destination face - aiFace *pDestFace = &pMesh->mFaces[ outIndex ]; - - const bool last = ( vertexIndex == pSourceFace->m_pVertices->size() - 1 ); - if (pSourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last) - { - pDestFace->mIndices[ outVertexIndex ] = newIndex; - outVertexIndex++; - } - - if (pSourceFace->m_PrimitiveType == aiPrimitiveType_POINT) - { - outIndex++; - outVertexIndex = 0; - } - else if (pSourceFace->m_PrimitiveType == aiPrimitiveType_LINE) - { - outVertexIndex = 0; - - if(!last) - outIndex++; - - if (vertexIndex) { - if(!last) { - pMesh->mVertices[ newIndex+1 ] = pMesh->mVertices[ newIndex ]; - if ( !pSourceFace->m_pNormals->empty() && !pModel->m_Normals.empty()) { - pMesh->mNormals[ newIndex+1 ] = pMesh->mNormals[newIndex ]; - } - if ( !pModel->m_TextureCoord.empty() ) { - for ( size_t i=0; i < pMesh->GetNumUVChannels(); i++ ) { - pMesh->mTextureCoords[ i ][ newIndex+1 ] = pMesh->mTextureCoords[ i ][ newIndex ]; - } - } - ++newIndex; - } - - pDestFace[-1].mIndices[1] = newIndex; - } - } - else if (last) { - outIndex++; - } - ++newIndex; - } - } + } + + if ( pMesh->mNumVertices <= newIndex ) { + throw DeadlyImportError("OBJ: bad vertex index"); + } + + // Get destination face + aiFace *pDestFace = &pMesh->mFaces[ outIndex ]; + + const bool last = ( vertexIndex == pSourceFace->m_pVertices->size() - 1 ); + if (pSourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last) + { + pDestFace->mIndices[ outVertexIndex ] = newIndex; + outVertexIndex++; + } + + if (pSourceFace->m_PrimitiveType == aiPrimitiveType_POINT) + { + outIndex++; + outVertexIndex = 0; + } + else if (pSourceFace->m_PrimitiveType == aiPrimitiveType_LINE) + { + outVertexIndex = 0; + + if(!last) + outIndex++; + + if (vertexIndex) { + if(!last) { + pMesh->mVertices[ newIndex+1 ] = pMesh->mVertices[ newIndex ]; + if ( !pSourceFace->m_pNormals->empty() && !pModel->m_Normals.empty()) { + pMesh->mNormals[ newIndex+1 ] = pMesh->mNormals[newIndex ]; + } + if ( !pModel->m_TextureCoord.empty() ) { + for ( size_t i=0; i < pMesh->GetNumUVChannels(); i++ ) { + pMesh->mTextureCoords[ i ][ newIndex+1 ] = pMesh->mTextureCoords[ i ][ newIndex ]; + } + } + ++newIndex; + } + + pDestFace[-1].mIndices[1] = newIndex; + } + } + else if (last) { + outIndex++; + } + ++newIndex; + } + } } // ------------------------------------------------------------------------------------------------ -// Counts all stored meshes +// Counts all stored meshes void ObjFileImporter::countObjects(const std::vector &rObjects, int &iNumMeshes) { - iNumMeshes = 0; - if ( rObjects.empty() ) - return; - - iNumMeshes += static_cast( rObjects.size() ); - for (std::vector::const_iterator it = rObjects.begin(); - it != rObjects.end(); - ++it) - { - if (!(*it)->m_SubObjects.empty()) - { - countObjects((*it)->m_SubObjects, iNumMeshes); - } - } + iNumMeshes = 0; + if ( rObjects.empty() ) + return; + + iNumMeshes += static_cast( rObjects.size() ); + for (std::vector::const_iterator it = rObjects.begin(); + it != rObjects.end(); + ++it) + { + if (!(*it)->m_SubObjects.empty()) + { + countObjects((*it)->m_SubObjects, iNumMeshes); + } + } } // ------------------------------------------------------------------------------------------------ -// Add clamp mode property to material if necessary +// Add clamp mode property to material if necessary void ObjFileImporter::addTextureMappingModeProperty(aiMaterial* mat, aiTextureType type, int clampMode) { - ai_assert( NULL != mat); - mat->AddProperty(&clampMode, 1, AI_MATKEY_MAPPINGMODE_U(type, 0)); - mat->AddProperty(&clampMode, 1, AI_MATKEY_MAPPINGMODE_V(type, 0)); + ai_assert( NULL != mat); + mat->AddProperty(&clampMode, 1, AI_MATKEY_MAPPINGMODE_U(type, 0)); + mat->AddProperty(&clampMode, 1, AI_MATKEY_MAPPINGMODE_V(type, 0)); } // ------------------------------------------------------------------------------------------------ -// Creates the material +// Creates the material void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pScene ) { - ai_assert( NULL != pScene ); - if ( NULL == pScene ) - return; - - const unsigned int numMaterials = (unsigned int) pModel->m_MaterialLib.size(); - pScene->mNumMaterials = 0; - if ( pModel->m_MaterialLib.empty() ) { - DefaultLogger::get()->debug("OBJ: no materials specified"); - return; - } - - pScene->mMaterials = new aiMaterial*[ numMaterials ]; - for ( unsigned int matIndex = 0; matIndex < numMaterials; matIndex++ ) - { - // Store material name - std::map::const_iterator it; - it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] ); - - // No material found, use the default material - if ( pModel->m_MaterialMap.end() == it ) - continue; - - aiMaterial* mat = new aiMaterial; - ObjFile::Material *pCurrentMaterial = (*it).second; - mat->AddProperty( &pCurrentMaterial->MaterialName, AI_MATKEY_NAME ); - - // convert illumination model - int sm = 0; - switch (pCurrentMaterial->illumination_model) - { - case 0: - sm = aiShadingMode_NoShading; - break; - case 1: - sm = aiShadingMode_Gouraud; - break; - case 2: - sm = aiShadingMode_Phong; - break; - default: - sm = aiShadingMode_Gouraud; - DefaultLogger::get()->error("OBJ: unexpected illumination model (0-2 recognized)"); - } - - mat->AddProperty( &sm, 1, AI_MATKEY_SHADING_MODEL); - - // multiplying the specular exponent with 2 seems to yield better results - pCurrentMaterial->shineness *= 4.f; - - // Adding material colors - mat->AddProperty( &pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT ); - mat->AddProperty( &pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE ); - mat->AddProperty( &pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR ); - mat->AddProperty( &pCurrentMaterial->emissive, 1, AI_MATKEY_COLOR_EMISSIVE ); - mat->AddProperty( &pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS ); - mat->AddProperty( &pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY ); - - // Adding refraction index - mat->AddProperty( &pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI ); - - // Adding textures - if ( 0 != pCurrentMaterial->texture.length ) - { - mat->AddProperty( &pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0)); - if (pCurrentMaterial->clamp[ObjFile::Material::TextureDiffuseType]) - { - addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE); - } - } - - if ( 0 != pCurrentMaterial->textureAmbient.length ) - { - mat->AddProperty( &pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0)); - if (pCurrentMaterial->clamp[ObjFile::Material::TextureAmbientType]) - { - addTextureMappingModeProperty(mat, aiTextureType_AMBIENT); - } - } - - if ( 0 != pCurrentMaterial->textureEmissive.length ) - mat->AddProperty( &pCurrentMaterial->textureEmissive, AI_MATKEY_TEXTURE_EMISSIVE(0)); - - if ( 0 != pCurrentMaterial->textureSpecular.length ) - { - mat->AddProperty( &pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0)); - if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularType]) - { - addTextureMappingModeProperty(mat, aiTextureType_SPECULAR); - } - } - - if ( 0 != pCurrentMaterial->textureBump.length ) - { - mat->AddProperty( &pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0)); - if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType]) - { - addTextureMappingModeProperty(mat, aiTextureType_HEIGHT); - } - } - - if ( 0 != pCurrentMaterial->textureNormal.length ) - { - mat->AddProperty( &pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0)); - if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType]) - { - addTextureMappingModeProperty(mat, aiTextureType_NORMALS); - } - } - - if ( 0 != pCurrentMaterial->textureDisp.length ) - { - mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) ); - if (pCurrentMaterial->clamp[ObjFile::Material::TextureDispType]) - { - addTextureMappingModeProperty(mat, aiTextureType_DISPLACEMENT); - } - } - - if ( 0 != pCurrentMaterial->textureOpacity.length ) - { - mat->AddProperty( &pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0)); - if (pCurrentMaterial->clamp[ObjFile::Material::TextureOpacityType]) - { - addTextureMappingModeProperty(mat, aiTextureType_OPACITY); - } - } - - if ( 0 != pCurrentMaterial->textureSpecularity.length ) - { - mat->AddProperty( &pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0)); - if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularityType]) - { - addTextureMappingModeProperty(mat, aiTextureType_SHININESS); - } - } - - // Store material property info in material array in scene - pScene->mMaterials[ pScene->mNumMaterials ] = mat; - pScene->mNumMaterials++; - } - - // Test number of created materials. - ai_assert( pScene->mNumMaterials == numMaterials ); + ai_assert( NULL != pScene ); + if ( NULL == pScene ) + return; + + const unsigned int numMaterials = (unsigned int) pModel->m_MaterialLib.size(); + pScene->mNumMaterials = 0; + if ( pModel->m_MaterialLib.empty() ) { + DefaultLogger::get()->debug("OBJ: no materials specified"); + return; + } + + pScene->mMaterials = new aiMaterial*[ numMaterials ]; + for ( unsigned int matIndex = 0; matIndex < numMaterials; matIndex++ ) + { + // Store material name + std::map::const_iterator it; + it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] ); + + // No material found, use the default material + if ( pModel->m_MaterialMap.end() == it ) + continue; + + aiMaterial* mat = new aiMaterial; + ObjFile::Material *pCurrentMaterial = (*it).second; + mat->AddProperty( &pCurrentMaterial->MaterialName, AI_MATKEY_NAME ); + + // convert illumination model + int sm = 0; + switch (pCurrentMaterial->illumination_model) + { + case 0: + sm = aiShadingMode_NoShading; + break; + case 1: + sm = aiShadingMode_Gouraud; + break; + case 2: + sm = aiShadingMode_Phong; + break; + default: + sm = aiShadingMode_Gouraud; + DefaultLogger::get()->error("OBJ: unexpected illumination model (0-2 recognized)"); + } + + mat->AddProperty( &sm, 1, AI_MATKEY_SHADING_MODEL); + + // multiplying the specular exponent with 2 seems to yield better results + pCurrentMaterial->shineness *= 4.f; + + // Adding material colors + mat->AddProperty( &pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT ); + mat->AddProperty( &pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE ); + mat->AddProperty( &pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR ); + mat->AddProperty( &pCurrentMaterial->emissive, 1, AI_MATKEY_COLOR_EMISSIVE ); + mat->AddProperty( &pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS ); + mat->AddProperty( &pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY ); + + // Adding refraction index + mat->AddProperty( &pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI ); + + // Adding textures + if ( 0 != pCurrentMaterial->texture.length ) + { + mat->AddProperty( &pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureDiffuseType]) + { + addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE); + } + } + + if ( 0 != pCurrentMaterial->textureAmbient.length ) + { + mat->AddProperty( &pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureAmbientType]) + { + addTextureMappingModeProperty(mat, aiTextureType_AMBIENT); + } + } + + if ( 0 != pCurrentMaterial->textureEmissive.length ) + mat->AddProperty( &pCurrentMaterial->textureEmissive, AI_MATKEY_TEXTURE_EMISSIVE(0)); + + if ( 0 != pCurrentMaterial->textureSpecular.length ) + { + mat->AddProperty( &pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularType]) + { + addTextureMappingModeProperty(mat, aiTextureType_SPECULAR); + } + } + + if ( 0 != pCurrentMaterial->textureBump.length ) + { + mat->AddProperty( &pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType]) + { + addTextureMappingModeProperty(mat, aiTextureType_HEIGHT); + } + } + + if ( 0 != pCurrentMaterial->textureNormal.length ) + { + mat->AddProperty( &pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType]) + { + addTextureMappingModeProperty(mat, aiTextureType_NORMALS); + } + } + + if( 0 != pCurrentMaterial->textureReflection[0].length ) + { + ObjFile::Material::TextureType type = 0 != pCurrentMaterial->textureReflection[1].length ? + ObjFile::Material::TextureReflectionCubeTopType : + ObjFile::Material::TextureReflectionSphereType; + + unsigned count = type == ObjFile::Material::TextureReflectionSphereType ? 1 : 6; + for( unsigned i = 0; i < count; i++ ) + mat->AddProperty(&pCurrentMaterial->textureReflection[i], AI_MATKEY_TEXTURE_REFLECTION(i)); + + if(pCurrentMaterial->clamp[type]) + //TODO addTextureMappingModeProperty should accept an index to handle clamp option for each + //texture of a cubemap + addTextureMappingModeProperty(mat, aiTextureType_REFLECTION); + } + + if ( 0 != pCurrentMaterial->textureDisp.length ) + { + mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) ); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureDispType]) + { + addTextureMappingModeProperty(mat, aiTextureType_DISPLACEMENT); + } + } + + if ( 0 != pCurrentMaterial->textureOpacity.length ) + { + mat->AddProperty( &pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureOpacityType]) + { + addTextureMappingModeProperty(mat, aiTextureType_OPACITY); + } + } + + if ( 0 != pCurrentMaterial->textureSpecularity.length ) + { + mat->AddProperty( &pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularityType]) + { + addTextureMappingModeProperty(mat, aiTextureType_SHININESS); + } + } + + // Store material property info in material array in scene + pScene->mMaterials[ pScene->mNumMaterials ] = mat; + pScene->mNumMaterials++; + } + + // Test number of created materials. + ai_assert( pScene->mNumMaterials == numMaterials ); } // ------------------------------------------------------------------------------------------------ -// Appends this node to the parent node +// Appends this node to the parent node void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild) { - // Checking preconditions - ai_assert( NULL != pParent ); - ai_assert( NULL != pChild ); - - // Assign parent to child - pChild->mParent = pParent; - - // If already children was assigned to the parent node, store them in a - std::vector temp; - if (pParent->mChildren != NULL) - { - ai_assert( 0 != pParent->mNumChildren ); - for (size_t index = 0; index < pParent->mNumChildren; index++) - { - temp.push_back(pParent->mChildren [ index ] ); - } - delete [] pParent->mChildren; - } - - // Copy node instances into parent node - pParent->mNumChildren++; - pParent->mChildren = new aiNode*[ pParent->mNumChildren ]; - for (size_t index = 0; index < pParent->mNumChildren-1; index++) - { - pParent->mChildren[ index ] = temp [ index ]; - } - pParent->mChildren[ pParent->mNumChildren-1 ] = pChild; + // Checking preconditions + ai_assert( NULL != pParent ); + ai_assert( NULL != pChild ); + + // Assign parent to child + pChild->mParent = pParent; + + // If already children was assigned to the parent node, store them in a + std::vector temp; + if (pParent->mChildren != NULL) + { + ai_assert( 0 != pParent->mNumChildren ); + for (size_t index = 0; index < pParent->mNumChildren; index++) + { + temp.push_back(pParent->mChildren [ index ] ); + } + delete [] pParent->mChildren; + } + + // Copy node instances into parent node + pParent->mNumChildren++; + pParent->mChildren = new aiNode*[ pParent->mNumChildren ]; + for (size_t index = 0; index < pParent->mNumChildren-1; index++) + { + pParent->mChildren[ index ] = temp [ index ]; + } + pParent->mChildren[ pParent->mNumChildren-1 ] = pChild; } // ------------------------------------------------------------------------------------------------ -} // Namespace Assimp +} // Namespace Assimp #endif // !! ASSIMP_BUILD_NO_OBJ_IMPORTER -- cgit v1.2.3