From 5ea06e1bb69e4b61c3f05160c9c38ed1187a5102 Mon Sep 17 00:00:00 2001 From: JeffH-BMG <37119778+JeffH-BMG@users.noreply.github.com> Date: Tue, 6 Mar 2018 14:50:02 -0500 Subject: [PATCH 01/15] Add support for texture file in PLY exports The PLY format has an unofficial way to specify an associated texture, using the "comment TextureFile" comment line. The PLY loader supports this, but the exporter does not. The change looks for a diffuse texture in the scene's materials, and if it finds one, it adds it to the exported mesh using "comment TextureFile". --- code/PlyExporter.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/code/PlyExporter.cpp b/code/PlyExporter.cpp index 0ddba0d2a..2d528c96c 100644 --- a/code/PlyExporter.cpp +++ b/code/PlyExporter.cpp @@ -148,6 +148,17 @@ PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool bina << aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' << aiGetVersionRevision() << ")" << endl; + // Look through materials for a diffuse texture, and add it if found + for ( unsigned int i = 0; i < pScene->mNumMaterials; ++i ) + { + const aiMaterial* const mat = pScene->mMaterials[i]; + aiString s; + if ( AI_SUCCESS == mat->Get( AI_MATKEY_TEXTURE_DIFFUSE( 0 ), s ) ) + { + mOutput << "comment TextureFile " << s.data << endl; + } + } + // TODO: probably want to check here rather than just assume something // definitely not good to always write float even if we might have double precision From 69742670dd55b256923bed0feb52d45146af97c8 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 9 Mar 2018 11:40:45 +0100 Subject: [PATCH 02/15] 3mf: use correct material assignment in case of multi-materials. --- code/3MFXmlTags.h | 1 + code/BaseImporter.cpp | 16 ++++----- code/D3MFExporter.cpp | 7 +++- code/D3MFExporter.h | 1 + code/D3MFImporter.cpp | 78 +++++++++++++++++++++++++++++++---------- code/D3MFOpcPackage.cpp | 59 ++++++++++++++++--------------- code/D3MFOpcPackage.h | 9 ++--- 7 files changed, 110 insertions(+), 61 deletions(-) diff --git a/code/3MFXmlTags.h b/code/3MFXmlTags.h index c4da2970d..feedf4538 100644 --- a/code/3MFXmlTags.h +++ b/code/3MFXmlTags.h @@ -74,6 +74,7 @@ namespace XmlTag { // Material definitions static const std::string basematerials = "basematerials"; + static const std::string basematerials_id = "id"; static const std::string basematerials_base = "base"; static const std::string basematerials_name = "name"; static const std::string basematerials_displaycolor = "displaycolor"; diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index e7736d8a4..67c743285 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -115,13 +115,12 @@ void BaseImporter::SetupProperties(const Importer* /*pImp*/) } // ------------------------------------------------------------------------------------------------ -void BaseImporter::GetExtensionList(std::set& extensions) -{ +void BaseImporter::GetExtensionList(std::set& extensions) { const aiImporterDesc* desc = GetInfo(); - ai_assert(desc != NULL); + ai_assert(desc != nullptr); const char* ext = desc->mFileExtensions; - ai_assert(ext != NULL); + ai_assert(ext != nullptr ); const char* last = ext; do { @@ -145,12 +144,13 @@ void BaseImporter::GetExtensionList(std::set& extensions) unsigned int searchBytes /* = 200 */, bool tokensSol /* false */) { - ai_assert( NULL != tokens ); + ai_assert( nullptr != tokens ); ai_assert( 0 != numTokens ); ai_assert( 0 != searchBytes); - if (!pIOHandler) + if ( nullptr == pIOHandler ) { return false; + } std::unique_ptr pStream (pIOHandler->Open(pFile)); if (pStream.get() ) { @@ -179,9 +179,9 @@ void BaseImporter::GetExtensionList(std::set& extensions) *cur2 = '\0'; std::string token; - for (unsigned int i = 0; i < numTokens;++i) { + for (unsigned int i = 0; i < numTokens; ++i ) { ai_assert( nullptr != tokens[i] ); - size_t len( strlen( tokens[ i ] ) ); + const size_t len( strlen( tokens[ i ] ) ); token.clear(); const char *ptr( tokens[ i ] ); for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) { diff --git a/code/D3MFExporter.cpp b/code/D3MFExporter.cpp index 91f06fc87..a74280af7 100644 --- a/code/D3MFExporter.cpp +++ b/code/D3MFExporter.cpp @@ -126,7 +126,6 @@ bool D3MFExporter::exportArchive( const char *file ) { return ok; } - bool D3MFExporter::exportContentTypes() { mContentOutput.clear(); @@ -177,6 +176,8 @@ bool D3MFExporter::export3DModel() { mModelOutput << "<" << XmlTag::resources << ">"; mModelOutput << std::endl; + writeBaseMaterials(); + writeObjects(); @@ -203,6 +204,10 @@ void D3MFExporter::writeHeader() { mModelOutput << std::endl; } +void D3MFExporter::writeBaseMaterials() { + +} + void D3MFExporter::writeObjects() { if ( nullptr == mScene->mRootNode ) { return; diff --git a/code/D3MFExporter.h b/code/D3MFExporter.h index 64967f68b..7e6e44e6e 100644 --- a/code/D3MFExporter.h +++ b/code/D3MFExporter.h @@ -76,6 +76,7 @@ public: protected: void writeHeader(); + void writeBaseMaterials(); void writeObjects(); void writeMesh( aiMesh *mesh ); void writeVertex( const aiVector3D &pos ); diff --git a/code/D3MFImporter.cpp b/code/D3MFImporter.cpp index fe5e260a4..7c0954524 100644 --- a/code/D3MFImporter.cpp +++ b/code/D3MFImporter.cpp @@ -70,9 +70,14 @@ namespace D3MF { class XmlSerializer { public: + using MatArray = std::vector; + using MatId2MatArray = std::map>; + XmlSerializer(XmlReader* xmlReader) : mMeshes() - , mMaterials() + , mMatArray() + , mActiveMatGroup( 99999999 ) + , mMatId2MatArray() , xmlReader(xmlReader){ // empty } @@ -109,10 +114,10 @@ public: std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes); - scene->mNumMaterials = mMaterials.size(); + scene->mNumMaterials = mMatArray.size(); if ( 0 != scene->mNumMaterials ) { scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ]; - std::copy( mMaterials.begin(), mMaterials.end(), scene->mMaterials ); + std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials ); } scene->mRootNode->mNumChildren = static_cast(children.size()); scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren](); @@ -162,7 +167,7 @@ private: return node.release(); } - aiMesh* ReadMesh() { + aiMesh *ReadMesh() { aiMesh* mesh = new aiMesh(); while(ReadToEndElement(D3MF::XmlTag::mesh)) { if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) { @@ -177,7 +182,6 @@ private: void ImportVertices(aiMesh* mesh) { std::vector vertices; - while(ReadToEndElement(D3MF::XmlTag::vertices)) { if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) { vertices.push_back(ReadVertex()); @@ -234,8 +238,27 @@ private: } void ReadBaseMaterials() { + std::vector MatIdArray; + const char *baseMaterialId( xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_id.c_str() ) ); + if ( nullptr != baseMaterialId ) { + unsigned int id = std::atoi( baseMaterialId ); + const size_t newMatIdx( mMatArray.size() ); + if ( id != mActiveMatGroup ) { + mActiveMatGroup = id; + MatId2MatArray::const_iterator it( mMatId2MatArray.find( id ) ); + if ( mMatId2MatArray.end() == it ) { + MatIdArray.clear(); + mMatId2MatArray[ id ] = MatIdArray; + } else { + MatIdArray = it->second; + } + } + MatIdArray.push_back( newMatIdx ); + mMatId2MatArray[ mActiveMatGroup ] = MatIdArray; + } + while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) { - mMaterials.push_back( readMaterialDef() ); + mMatArray.push_back( readMaterialDef() ); xmlReader->read(); } } @@ -285,24 +308,37 @@ private: return true; } + void assignDiffuseColor( aiMaterial *mat ) { + const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() ); + aiColor4D diffuse; + if ( parseColor( color, diffuse ) ) { + mat->AddProperty( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE ); + } + + } aiMaterial *readMaterialDef() { aiMaterial *mat( nullptr ); const char *name( nullptr ); - const char *color( nullptr ); const std::string nodeName( xmlReader->getNodeName() ); if ( nodeName == D3MF::XmlTag::basematerials_base ) { name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() ); - + std::string stdMatName; aiString matName; - matName.Set( name ); + std::string strId( to_string( mActiveMatGroup ) ); + stdMatName += "id"; + stdMatName += strId; + stdMatName += "_"; + if ( nullptr != name ) { + stdMatName += std::string( name ); + } else { + stdMatName += "basemat"; + } + matName.Set( stdMatName ); + mat = new aiMaterial; mat->AddProperty( &matName, AI_MATKEY_NAME ); - color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() ); - aiColor4D diffuse; - if ( parseColor( color, diffuse ) ) { - mat->AddProperty( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE ); - } + assignDiffuseColor( mat ); } return mat; @@ -339,7 +375,9 @@ private: private: std::vector mMeshes; - std::vector mMaterials; + MatArray mMatArray; + unsigned int mActiveMatGroup; + MatId2MatArray mMatId2MatArray; XmlReader* xmlReader; }; @@ -370,14 +408,16 @@ D3MFImporter::~D3MFImporter() { // empty } -bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { - const std::string extension = GetExtension(pFile); +bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const { + const std::string extension( GetExtension( filename ) ); if(extension == Extension ) { return true; } else if ( !extension.length() || checkSig ) { - if (nullptr == pIOHandler ) { - return true; + if ( nullptr == pIOHandler ) { + return false; } + D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename ); + return opcPackage.validate(); } return false; diff --git a/code/D3MFOpcPackage.cpp b/code/D3MFOpcPackage.cpp index a7039d34e..81d610e15 100644 --- a/code/D3MFOpcPackage.cpp +++ b/code/D3MFOpcPackage.cpp @@ -247,13 +247,13 @@ private: // ------------------------------------------------------------------------------------------------ // Constructor. D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile) -: m_ZipFileHandle(NULL) +: m_ZipFileHandle( nullptr ) , m_ArchiveMap() { if (! rFile.empty()) { zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler); m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping); - if(m_ZipFileHandle != NULL) { + if(m_ZipFileHandle != nullptr ) { mapArchive(); } } @@ -267,32 +267,32 @@ D3MFZipArchive::~D3MFZipArchive() { } m_ArchiveMap.clear(); - if(m_ZipFileHandle != NULL) { + if(m_ZipFileHandle != nullptr) { unzClose(m_ZipFileHandle); - m_ZipFileHandle = NULL; + m_ZipFileHandle = nullptr; } } // ------------------------------------------------------------------------------------------------ // Returns true, if the archive is already open. bool D3MFZipArchive::isOpen() const { - return (m_ZipFileHandle != NULL); + return (m_ZipFileHandle != nullptr ); } // ------------------------------------------------------------------------------------------------ // Returns true, if the filename is part of the archive. bool D3MFZipArchive::Exists(const char* pFile) const { - ai_assert(pFile != NULL); + ai_assert(pFile != nullptr ); - bool exist = false; + if ( pFile == nullptr ) { + return false; + } - if (pFile != NULL) { - std::string rFile(pFile); - std::map::const_iterator it = m_ArchiveMap.find(rFile); - - if(it != m_ArchiveMap.end()) { - exist = true; - } + std::string rFile(pFile); + std::map::const_iterator it = m_ArchiveMap.find(rFile); + bool exist( false ); + if(it != m_ArchiveMap.end()) { + exist = true; } return exist; @@ -434,8 +434,8 @@ public: std::vector m_relationShips; }; -// ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) : mRootStream(nullptr) , mZipArchive() { @@ -460,7 +460,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) { rootFile = rootFile.substr( 1 ); if ( rootFile[ 0 ] == '/' ) { - // deal with zipbug + // deal with zip-bug rootFile = rootFile.substr( 1 ); } } @@ -470,18 +470,9 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) mRootStream = mZipArchive->Open(rootFile.c_str()); ai_assert( mRootStream != nullptr ); if ( nullptr == mRootStream ) { - throw DeadlyExportError( "Cannot open rootfile in archive : " + rootFile ); + throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile ); } - // const size_t size = zipArchive->FileSize(); - // m_Data.resize( size ); - - // const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size ); - // if ( readSize != size ) - // { - // m_Data.clear(); - // return false; - // } mZipArchive->Close( fileStream ); } else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { @@ -498,6 +489,16 @@ IOStream* D3MFOpcPackage::RootStream() const { return mRootStream; } +static const std::string ModelRef = "3D/3dmodel.model"; + +bool D3MFOpcPackage::validate() { + if ( nullptr == mRootStream || nullptr == mZipArchive ) { + return false; + } + + return mZipArchive->Exists( ModelRef.c_str() ); +} + std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) { std::unique_ptr xmlStream(new CIrrXML_IOStreamReader(stream)); std::unique_ptr xml(irr::io::createIrrXMLReader(xmlStream.get())); @@ -508,14 +509,14 @@ std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) { return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; }); - if(itr == reader.m_relationShips.end()) - throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE); + if ( itr == reader.m_relationShips.end() ) { + throw DeadlyImportError( "Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE ); + } return (*itr)->target; } } // Namespace D3MF - } // Namespace Assimp #endif //ASSIMP_BUILD_NO_3MF_IMPORTER diff --git a/code/D3MFOpcPackage.h b/code/D3MFOpcPackage.h index 8cf08d092..b49740eff 100644 --- a/code/D3MFOpcPackage.h +++ b/code/D3MFOpcPackage.h @@ -51,8 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace D3MF { -typedef irr::io::IrrXMLReader XmlReader; -typedef std::shared_ptr XmlReaderPtr; +using XmlReader = irr::io::IrrXMLReader ; +using XmlReaderPtr = std::shared_ptr ; struct OpcPackageRelationship { std::string id; @@ -67,6 +67,7 @@ public: D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile); ~D3MFOpcPackage(); IOStream* RootStream() const; + bool validate(); protected: std::string ReadPackageRootRelationship(IOStream* stream); @@ -76,7 +77,7 @@ private: std::unique_ptr mZipArchive; }; -} -} +} // Namespace D3MF +} // Namespace Assimp #endif // D3MFOPCPACKAGE_H From 6668eeb68eaeeff2b0686d07d7ec6e1cdf88c882 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 9 Mar 2018 19:03:05 +0100 Subject: [PATCH 03/15] Fix possible nullptr dereferencing. --- code/D3MFExporter.cpp | 42 ++++++++++++++++++++++++++++++++++++-- include/assimp/fast_atof.h | 2 -- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/code/D3MFExporter.cpp b/code/D3MFExporter.cpp index a74280af7..98b15b10b 100644 --- a/code/D3MFExporter.cpp +++ b/code/D3MFExporter.cpp @@ -49,8 +49,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include - +#include #include + #include "3MFXmlTags.h" #include "D3MFOpcPackage.h" @@ -204,8 +205,45 @@ void D3MFExporter::writeHeader() { mModelOutput << std::endl; } -void D3MFExporter::writeBaseMaterials() { +static std::string to_hex( int to_convert ) { + std::string result; + std::stringstream ss; + ss << std::hex << to_convert; + ss >> result; + return result; +} +void D3MFExporter::writeBaseMaterials() { + mModelOutput << "\n"; + for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) { + aiMaterial *mat = mScene->mMaterials[ i ]; + std::string strName; + aiString name; + if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) { + strName = "basemat_" + to_string( i ); + } else { + strName = name.C_Str(); + } + std::string hexDiffuseColor; + aiColor4D color; + if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) { + hexDiffuseColor = "#"; + std::string tmp; + tmp = to_hex( color.r ); + hexDiffuseColor += tmp; + tmp = to_hex( color.g ); + hexDiffuseColor += tmp; + tmp = to_hex( color.b ); + hexDiffuseColor += tmp; + tmp = to_hex( color.a ); + hexDiffuseColor += tmp; + } else { + hexDiffuseColor = "#FFFFFFFF"; + } + + mModelOutput << "\n"; + } + mModelOutput << "\n"; } void D3MFExporter::writeObjects() { diff --git a/include/assimp/fast_atof.h b/include/assimp/fast_atof.h index fced5307a..e66f1b37d 100644 --- a/include/assimp/fast_atof.h +++ b/include/assimp/fast_atof.h @@ -146,7 +146,6 @@ uint8_t HexOctetToDecimal(const char* in) { return ((uint8_t)HexDigitToDecimal(in[0])<<4)+(uint8_t)HexDigitToDecimal(in[1]); } - // ------------------------------------------------------------------------------------ // signed variant of strtoul10 // ------------------------------------------------------------------------------------ @@ -353,7 +352,6 @@ ai_real fast_atof(const char* c) { return ret; } - inline ai_real fast_atof( const char* c, const char** cout) { ai_real ret(0.0); From 336a09ee0e47f5520eb3032d7b377982176fbe6d Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 9 Mar 2018 23:35:12 +0100 Subject: [PATCH 04/15] add material reference to faces. --- code/ConvertToLHProcess.cpp | 26 +++++++++++++++++--------- code/D3MFExporter.cpp | 9 ++++++--- code/D3MFExporter.h | 2 +- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/code/ConvertToLHProcess.cpp b/code/ConvertToLHProcess.cpp index 47e2fb949..ba8371439 100644 --- a/code/ConvertToLHProcess.cpp +++ b/code/ConvertToLHProcess.cpp @@ -91,12 +91,14 @@ void MakeLeftHandedProcess::Execute( aiScene* pScene) ProcessNode( pScene->mRootNode, aiMatrix4x4()); // process the meshes accordingly - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) - ProcessMesh( pScene->mMeshes[a]); + for ( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) { + ProcessMesh( pScene->mMeshes[ a ] ); + } // process the materials accordingly - for( unsigned int a = 0; a < pScene->mNumMaterials; ++a) - ProcessMaterial( pScene->mMaterials[a]); + for ( unsigned int a = 0; a < pScene->mNumMaterials; ++a ) { + ProcessMaterial( pScene->mMaterials[ a ] ); + } // transform all animation channels as well for( unsigned int a = 0; a < pScene->mNumAnimations; a++) @@ -136,8 +138,11 @@ void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pPare // ------------------------------------------------------------------------------------------------ // Converts a single mesh to left handed coordinates. -void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) -{ +void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) { + if ( nullptr == pMesh ) { + DefaultLogger::get()->error( "Nullptr to mesh found." ); + return; + } // mirror positions, normals and stuff along the Z axis for( size_t a = 0; a < pMesh->mNumVertices; ++a) { @@ -173,8 +178,12 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) // ------------------------------------------------------------------------------------------------ // Converts a single material to left handed coordinates. -void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) -{ +void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) { + if ( nullptr == _mat ) { + DefaultLogger::get()->error( "Nullptr to aiMaterial found." ); + return; + } + aiMaterial* mat = (aiMaterial*)_mat; for (unsigned int a = 0; a < mat->mNumProperties;++a) { aiMaterialProperty* prop = mat->mProperties[a]; @@ -183,7 +192,6 @@ void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) { ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */ aiVector3D* pff = (aiVector3D*)prop->mData; - pff->z *= -1.f; } } diff --git a/code/D3MFExporter.cpp b/code/D3MFExporter.cpp index 98b15b10b..7c75178e6 100644 --- a/code/D3MFExporter.cpp +++ b/code/D3MFExporter.cpp @@ -285,7 +285,9 @@ void D3MFExporter::writeMesh( aiMesh *mesh ) { } mModelOutput << "" << std::endl; - writeFaces( mesh ); + const unsigned int matIdx( mesh->mMaterialIndex ); + + writeFaces( mesh, matIdx ); mModelOutput << "" << std::endl; } @@ -295,7 +297,7 @@ void D3MFExporter::writeVertex( const aiVector3D &pos ) { mModelOutput << std::endl; } -void D3MFExporter::writeFaces( aiMesh *mesh ) { +void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) { if ( nullptr == mesh ) { return; } @@ -307,7 +309,8 @@ void D3MFExporter::writeFaces( aiMesh *mesh ) { for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) { aiFace ¤tFace = mesh->mFaces[ i ]; mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\"" - << currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ] << "\"/>"; + << currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ] + << "\" pid=\"1\" p1=\""+to_string(matIdx)+"\" />"; mModelOutput << std::endl; } mModelOutput << ""; diff --git a/code/D3MFExporter.h b/code/D3MFExporter.h index 7e6e44e6e..b553e0ab5 100644 --- a/code/D3MFExporter.h +++ b/code/D3MFExporter.h @@ -80,7 +80,7 @@ protected: void writeObjects(); void writeMesh( aiMesh *mesh ); void writeVertex( const aiVector3D &pos ); - void writeFaces( aiMesh *mesh ); + void writeFaces( aiMesh *mesh, unsigned int matIdx ); void writeBuild(); void exportContentTyp( const std::string &filename ); void writeModelToArchive( const std::string &folder, const std::string &modelName ); From 017b7d1a2f51a4f62047c98f987704fc9fabebe4 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 11 Mar 2018 20:15:25 +0100 Subject: [PATCH 05/15] 3MF: add missig tags for meta data. --- code/3MFXmlTags.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/3MFXmlTags.h b/code/3MFXmlTags.h index feedf4538..e869c33c1 100644 --- a/code/3MFXmlTags.h +++ b/code/3MFXmlTags.h @@ -45,6 +45,10 @@ namespace Assimp { namespace D3MF { namespace XmlTag { + // Meta-data + static const std::string meta = "metadata"; + static const std::string meta_name = "name"; + // Model-data specific tags static const std::string model = "model"; static const std::string model_unit = "unit"; From c8ae0bbb3d43384fde27c28c93343b0f885dc5e8 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 11 Mar 2018 20:15:49 +0100 Subject: [PATCH 06/15] 3MF: fix model folder desc. --- code/D3MFExporter.cpp | 25 +++++++++++-------------- code/D3MFImporter.cpp | 6 ++---- include/assimp/StringUtils.h | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/code/D3MFExporter.cpp b/code/D3MFExporter.cpp index 7c75178e6..b89e81ce6 100644 --- a/code/D3MFExporter.cpp +++ b/code/D3MFExporter.cpp @@ -153,7 +153,11 @@ bool D3MFExporter::exportRelations() { mRelOutput << ""; for ( size_t i = 0; i < mRelations.size(); ++i ) { - mRelOutput << "target << "\" "; + if ( mRelations[ i ]->target[ 0 ] == '/' ) { + mRelOutput << "target << "\" "; + } else { + mRelOutput << "target << "\" "; + } mRelOutput << "Id=\"" << mRelations[i]->id << "\" "; mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />"; mRelOutput << std::endl; @@ -205,14 +209,6 @@ void D3MFExporter::writeHeader() { mModelOutput << std::endl; } -static std::string to_hex( int to_convert ) { - std::string result; - std::stringstream ss; - ss << std::hex << to_convert; - ss >> result; - return result; -} - void D3MFExporter::writeBaseMaterials() { mModelOutput << "\n"; for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) { @@ -229,19 +225,20 @@ void D3MFExporter::writeBaseMaterials() { if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) { hexDiffuseColor = "#"; std::string tmp; - tmp = to_hex( color.r ); + + tmp = DecimalToHexa( color.r ); hexDiffuseColor += tmp; - tmp = to_hex( color.g ); + tmp = DecimalToHexa( color.g ); hexDiffuseColor += tmp; - tmp = to_hex( color.b ); + tmp = DecimalToHexa( color.b ); hexDiffuseColor += tmp; - tmp = to_hex( color.a ); + tmp = DecimalToHexa( color.a ); hexDiffuseColor += tmp; } else { hexDiffuseColor = "#FFFFFFFF"; } - mModelOutput << "\n"; + mModelOutput << "\n"; } mModelOutput << "\n"; } diff --git a/code/D3MFImporter.cpp b/code/D3MFImporter.cpp index 7c0954524..1732a5a8a 100644 --- a/code/D3MFImporter.cpp +++ b/code/D3MFImporter.cpp @@ -259,7 +259,6 @@ private: while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) { mMatArray.push_back( readMaterialDef() ); - xmlReader->read(); } } @@ -398,7 +397,6 @@ static const aiImporterDesc desc = { Extension.c_str() }; - D3MFImporter::D3MFImporter() : BaseImporter() { // empty @@ -431,8 +429,8 @@ const aiImporterDesc *D3MFImporter::GetInfo() const { return &desc; } -void D3MFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { - D3MF::D3MFOpcPackage opcPackage(pIOHandler, pFile); +void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) { + D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename); std::unique_ptr xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream())); std::unique_ptr xmlReader(irr::io::createIrrXMLReader(xmlStream.get())); diff --git a/include/assimp/StringUtils.h b/include/assimp/StringUtils.h index 3c3afd264..157454126 100644 --- a/include/assimp/StringUtils.h +++ b/include/assimp/StringUtils.h @@ -55,7 +55,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// @return The number of written characters if the buffer size was big enough. If an encoding error occurs, a negative number is returned. #if defined(_MSC_VER) && _MSC_VER < 1900 - inline int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { + inline + int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { int count(-1); if (0 != size) { count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); @@ -67,7 +68,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. return count; } - inline int ai_snprintf(char *outBuf, size_t size, const char *format, ...) { + inline + int ai_snprintf(char *outBuf, size_t size, const char *format, ...) { int count; va_list ap; @@ -82,14 +84,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # define ai_snprintf snprintf #endif +/// @fn to_string +/// @brief The portable version of to_string ( some gcc-versions on embedded devices are not supporting this). +/// @param value The value to write into the std::string. +/// @return The value as a std::string template inline std::string to_string( T value ) { std::ostringstream os; os << value; + return os.str(); } +/// @fn ai_strtof +/// @brief The portable version of strtof. +/// @param begin The first character of the string. +/// @param end The last character +/// @return The float value, 0.0f in cas of an error. inline float ai_strtof( const char *begin, const char *end ) { if ( nullptr == begin ) { @@ -107,5 +119,23 @@ float ai_strtof( const char *begin, const char *end ) { return val; } -#endif // INCLUDED_AI_STRINGUTILS_H +/// @fn DecimalToHexa +/// @brief The portable to convert a decimal value into a hexadecimal string. +/// @param toConvert Value to convert +/// @return The hexadecimal string, is empty in case of an error. +template +inline +std::string DecimalToHexa( T toConvert ) { + std::string result; + std::stringstream ss; + ss << std::hex << toConvert; + ss >> result; + for ( size_t i = 0; i < result.size(); ++i ) { + result[ i ] = toupper( result[ i ] ); + } + + return result; +} + +#endif // INCLUDED_AI_STRINGUTILS_H From c7ac32f891a16cc49fcca9b656feec75c116de76 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 12 Mar 2018 22:28:00 +0100 Subject: [PATCH 07/15] fix naming readout + export. --- code/D3MFImporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/D3MFImporter.cpp b/code/D3MFImporter.cpp index 1732a5a8a..fce2743fe 100644 --- a/code/D3MFImporter.cpp +++ b/code/D3MFImporter.cpp @@ -133,11 +133,11 @@ private: const char *attrib( nullptr ); std::string name, type; - attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() ); + attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() ); if ( nullptr != attrib ) { name = attrib; } - attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() ); + attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() ); if ( nullptr != attrib ) { type = attrib; } From f11d4902c626e08a949f83eefcb38483c3edc5e9 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 13 Mar 2018 17:50:34 +0100 Subject: [PATCH 08/15] fix CanRead-method for the 3MF-Importer. --- code/D3MFImporter.cpp | 3 +++ code/D3MFOpcPackage.cpp | 9 +++++++++ code/D3MFOpcPackage.h | 3 ++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/code/D3MFImporter.cpp b/code/D3MFImporter.cpp index fce2743fe..c5b4a8c91 100644 --- a/code/D3MFImporter.cpp +++ b/code/D3MFImporter.cpp @@ -414,6 +414,9 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo if ( nullptr == pIOHandler ) { return false; } + if ( !D3MF::D3MFOpcPackage::isZipArchive( pIOHandler, filename ) ) { + return false; + } D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename ); return opcPackage.validate(); } diff --git a/code/D3MFOpcPackage.cpp b/code/D3MFOpcPackage.cpp index 81d610e15..2f7c8a25e 100644 --- a/code/D3MFOpcPackage.cpp +++ b/code/D3MFOpcPackage.cpp @@ -499,6 +499,15 @@ bool D3MFOpcPackage::validate() { return mZipArchive->Exists( ModelRef.c_str() ); } +bool D3MFOpcPackage::isZipArchive( IOSystem* pIOHandler, const std::string& rFile ) { + D3MF::D3MFZipArchive ar( pIOHandler, rFile ); + if ( !ar.isOpen() ) { + return false; + } + + return true; +} + std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) { std::unique_ptr xmlStream(new CIrrXML_IOStreamReader(stream)); std::unique_ptr xml(irr::io::createIrrXMLReader(xmlStream.get())); diff --git a/code/D3MFOpcPackage.h b/code/D3MFOpcPackage.h index b49740eff..6d7b3d478 100644 --- a/code/D3MFOpcPackage.h +++ b/code/D3MFOpcPackage.h @@ -64,10 +64,11 @@ class D3MFZipArchive; class D3MFOpcPackage { public: - D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile); + D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile ); ~D3MFOpcPackage(); IOStream* RootStream() const; bool validate(); + static bool isZipArchive( IOSystem* pIOHandler, const std::string& rFile ); protected: std::string ReadPackageRootRelationship(IOStream* stream); From 6b9add5594185afdc90f58c385bb78cf7699fa70 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 13 Mar 2018 18:19:10 +0100 Subject: [PATCH 09/15] fix compiler warning fr 64 bit --- code/D3MFImporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/D3MFImporter.cpp b/code/D3MFImporter.cpp index c5b4a8c91..3fffa5aeb 100644 --- a/code/D3MFImporter.cpp +++ b/code/D3MFImporter.cpp @@ -114,7 +114,7 @@ public: std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes); - scene->mNumMaterials = mMatArray.size(); + scene->mNumMaterials = static_cast( mMatArray.size() ); if ( 0 != scene->mNumMaterials ) { scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ]; std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials ); From f857d72dbbb07177e80f80af639f1c7e685f7ddd Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 13 Mar 2018 18:56:47 +0100 Subject: [PATCH 10/15] add roundtrip test for 3mf. --- test/unit/utD3MFImportExport.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/unit/utD3MFImportExport.cpp b/test/unit/utD3MFImportExport.cpp index 3aefeba84..dd54b3042 100644 --- a/test/unit/utD3MFImportExport.cpp +++ b/test/unit/utD3MFImportExport.cpp @@ -86,4 +86,11 @@ TEST_F( utD3MFImporterExporter, export3MFtoMemTest ) { EXPECT_TRUE( exporterTest() ); } +TEST_F( utD3MFImporterExporter, roundtrip3MFtoMemTest ) { + EXPECT_TRUE( exporterTest() ); + + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "test.3mf", 0 ); +} + #endif // ASSIMP_BUILD_NO_EXPORT From 18e9aa13d6a603983e25675bb7a376caf45c3c02 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 13 Mar 2018 19:15:56 +0100 Subject: [PATCH 11/15] fix vs2017-compiler-warning c4002: tr1 is deprecated. --- test/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a9dfaf83f..049dbcdd2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -45,7 +45,9 @@ INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/include ${Assimp_SOURCE_DIR}/code ) - +if (MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING") +endif() # Add the temporary output directories to the library path to make sure the # Assimp library can be found, even if it is not installed system-wide yet. LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${AssetImporter_BINARY_DIR}/lib ) From 20c817bc36e9f7cc16abbba8a0b613de910faf43 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 13 Mar 2018 19:42:06 +0100 Subject: [PATCH 12/15] Update utD3MFImportExport.cpp Fix compiler warning: unused var. --- test/unit/utD3MFImportExport.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/utD3MFImportExport.cpp b/test/unit/utD3MFImportExport.cpp index dd54b3042..e8797d74d 100644 --- a/test/unit/utD3MFImportExport.cpp +++ b/test/unit/utD3MFImportExport.cpp @@ -91,6 +91,7 @@ TEST_F( utD3MFImporterExporter, roundtrip3MFtoMemTest ) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "test.3mf", 0 ); + EXPECT_NE( nullptr, scene ); } #endif // ASSIMP_BUILD_NO_EXPORT From 4c023c3818252c1102c5dc2bca200d0a9fff9d8b Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 13 Mar 2018 21:40:23 +0100 Subject: [PATCH 13/15] fix unittest folder for roundtriptest. --- code/IRRLoader.cpp | 20 ++++++++------------ test/unit/utD3MFImportExport.cpp | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/code/IRRLoader.cpp b/code/IRRLoader.cpp index fbec3da00..66d15c5c4 100644 --- a/code/IRRLoader.cpp +++ b/code/IRRLoader.cpp @@ -100,26 +100,22 @@ IRRImporter::~IRRImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const -{ - /* NOTE: A simple check for the file extension is not enough - * here. Irrmesh and irr are easy, but xml is too generic - * and could be collada, too. So we need to open the file and - * search for typical tokens. - */ +bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { const std::string extension = GetExtension(pFile); - - if (extension == "irr")return true; - else if (extension == "xml" || checkSig) - { + if ( extension == "irr" ) { + return true; + } else if (extension == "xml" || checkSig) { /* If CanRead() is called in order to check whether we * support a specific file extension in general pIOHandler * might be NULL and it's our duty to return true here. */ - if (!pIOHandler)return true; + if ( nullptr == pIOHandler ) { + return true; + } const char* tokens[] = {"irr_scene"}; return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); } + return false; } diff --git a/test/unit/utD3MFImportExport.cpp b/test/unit/utD3MFImportExport.cpp index e8797d74d..c5fdd003b 100644 --- a/test/unit/utD3MFImportExport.cpp +++ b/test/unit/utD3MFImportExport.cpp @@ -90,7 +90,7 @@ TEST_F( utD3MFImporterExporter, roundtrip3MFtoMemTest ) { EXPECT_TRUE( exporterTest() ); Assimp::Importer importer; - const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "test.3mf", 0 ); + const aiScene *scene = importer.ReadFile( "test.3mf", 0 ); EXPECT_NE( nullptr, scene ); } From 5cf6509fb51c648a2c155ed82920a7ae2947ea2d Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 14 Mar 2018 20:42:42 +0100 Subject: [PATCH 14/15] closes https://github.com/assimp/assimp/issues/1120: use euler angles for pre- and post-rotation. --- code/FBXConverter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index 5d732c7b2..9bb023b4e 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -643,14 +643,14 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector if ( ok && PreRotation.SquareLength() > zero_epsilon ) { is_complex = true; - GetRotationMatrix( rot, PreRotation, chain[ TransformationComp_PreRotation ] ); + GetRotationMatrix( Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[ TransformationComp_PreRotation ] ); } const aiVector3D& PostRotation = PropertyGet( props, "PostRotation", ok ); if ( ok && PostRotation.SquareLength() > zero_epsilon ) { is_complex = true; - GetRotationMatrix( rot, PostRotation, chain[ TransformationComp_PostRotation ] ); + GetRotationMatrix( Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[ TransformationComp_PostRotation ] ); } const aiVector3D& RotationPivot = PropertyGet( props, "RotationPivot", ok ); From 2d980c16f0359c3c2e78bd71c86627aa97c705b0 Mon Sep 17 00:00:00 2001 From: Sergey Gonchar Date: Thu, 15 Mar 2018 21:41:40 -0700 Subject: [PATCH 15/15] Support Maya 2018 Collada Export with blendshapes and bones controllers for a mesh --- code/ColladaParser.cpp | 16 ++++++++++++++++ code/ColladaParser.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/code/ColladaParser.cpp b/code/ColladaParser.cpp index d62c5cafc..d96ac0d39 100644 --- a/code/ColladaParser.cpp +++ b/code/ColladaParser.cpp @@ -222,6 +222,7 @@ void ColladaParser::ReadStructure() } PostProcessRootAnimations(); + PostProcessControllers(); } // ------------------------------------------------------------------------------------------------ @@ -360,6 +361,21 @@ void ColladaParser::ReadAnimationClipLibrary() } } +void ColladaParser::PostProcessControllers() +{ + for (ControllerLibrary::iterator it = mControllerLibrary.begin(); it != mControllerLibrary.end(); ++it) + { + std::string meshId = it->second.mMeshId; + ControllerLibrary::iterator findItr = mControllerLibrary.find(meshId); + while(findItr != mControllerLibrary.end()) { + meshId = findItr->second.mMeshId; + findItr = mControllerLibrary.find(meshId); + } + + it->second.mMeshId = meshId; + } +} + // ------------------------------------------------------------------------------------------------ // Re-build animations from animation clip library, if present, otherwise combine single-channel animations void ColladaParser::PostProcessRootAnimations() diff --git a/code/ColladaParser.h b/code/ColladaParser.h index 566386840..21f741551 100644 --- a/code/ColladaParser.h +++ b/code/ColladaParser.h @@ -87,6 +87,9 @@ namespace Assimp /** Reads the animation clip library */ void ReadAnimationClipLibrary(); + /** Unwrap controllers dependency hierarchy */ + void PostProcessControllers(); + /** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */ void PostProcessRootAnimations();