diff --git a/code/ObjFileImporter.cpp b/code/ObjFileImporter.cpp index e4046b53b..7bf6154df 100644 --- a/code/ObjFileImporter.cpp +++ b/code/ObjFileImporter.cpp @@ -133,15 +133,16 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, TextFileToBuffer(file.get(),m_Buffer); // Get the model name - std::string strModelName; + std::string modelName, folderName; 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; + if ( pos != std::string::npos ) { + modelName = pFile.substr(pos+1, pFile.size() - pos - 1); + folderName = pFile.substr( 0, pos ); + if ( folderName.empty() ) { + pIOHandler->PushDirectory( folderName ); + } + } else { + modelName = pFile; } // process all '\' @@ -161,13 +162,18 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, } // parse the file into a temporary representation - ObjFileParser parser(m_Buffer, strModelName, pIOHandler); + ObjFileParser parser(m_Buffer, modelName, 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(); + + // Pop directory stack + if ( pIOHandler->StackSize() > 0 ) { + pIOHandler->PopDirectory(); + } } // ------------------------------------------------------------------------------------------------ diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index b2194a747..346c734fc 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -61,21 +61,21 @@ const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME; // ------------------------------------------------------------------- // Constructor with loaded data and directories. -ObjFileParser::ObjFileParser(std::vector &Data,const std::string &strModelName, IOSystem *io ) : - m_DataIt(Data.begin()), - m_DataItEnd(Data.end()), +ObjFileParser::ObjFileParser(std::vector &data,const std::string &modelName, IOSystem *io ) : + m_DataIt(data.begin()), + m_DataItEnd(data.end()), m_pModel(NULL), m_uiLine(0), m_pIO( io ) { - std::fill_n(m_buffer,BUFFERSIZE,0); + std::fill_n(m_buffer,Buffersize,0); // Create the model instance to store all the data m_pModel = new ObjFile::Model(); - m_pModel->m_ModelName = strModelName; + m_pModel->m_ModelName = modelName; // create default material and store it - m_pModel->m_pDefaultMaterial = new ObjFile::Material(); + m_pModel->m_pDefaultMaterial = new ObjFile::Material; m_pModel->m_pDefaultMaterial->MaterialName.Set( DEFAULT_MATERIAL ); m_pModel->m_MaterialLib.push_back( DEFAULT_MATERIAL ); m_pModel->m_MaterialMap[ DEFAULT_MATERIAL ] = m_pModel->m_pDefaultMaterial; @@ -248,20 +248,20 @@ void ObjFileParser::getVector( std::vector &point3d_array ) { } float x, y, z; if( 2 == numComponents ) { - copyNextWord( m_buffer, BUFFERSIZE ); + copyNextWord( m_buffer, Buffersize ); x = ( float ) fast_atof( m_buffer ); - copyNextWord( m_buffer, BUFFERSIZE ); + copyNextWord( m_buffer, Buffersize ); y = ( float ) fast_atof( m_buffer ); z = 0.0; } else if( 3 == numComponents ) { - copyNextWord( m_buffer, BUFFERSIZE ); + copyNextWord( m_buffer, Buffersize ); x = ( float ) fast_atof( m_buffer ); - copyNextWord( m_buffer, BUFFERSIZE ); + copyNextWord( m_buffer, Buffersize ); y = ( float ) fast_atof( m_buffer ); - copyNextWord( m_buffer, BUFFERSIZE ); + copyNextWord( m_buffer, Buffersize ); z = ( float ) fast_atof( m_buffer ); } else { throw DeadlyImportError( "OBJ: Invalid number of components" ); @@ -274,13 +274,13 @@ void ObjFileParser::getVector( std::vector &point3d_array ) { // Get values for a new 3D vector instance void ObjFileParser::getVector3(std::vector &point3d_array) { float x, y, z; - copyNextWord(m_buffer, BUFFERSIZE); + copyNextWord(m_buffer, Buffersize); x = (float) fast_atof(m_buffer); - copyNextWord(m_buffer, BUFFERSIZE); + copyNextWord(m_buffer, Buffersize); y = (float) fast_atof(m_buffer); - copyNextWord( m_buffer, BUFFERSIZE ); + copyNextWord( m_buffer, Buffersize ); z = ( float ) fast_atof( m_buffer ); point3d_array.push_back( aiVector3D( x, y, z ) ); @@ -291,10 +291,10 @@ void ObjFileParser::getVector3(std::vector &point3d_array) { // Get values for a new 2D vector instance void ObjFileParser::getVector2( std::vector &point2d_array ) { float x, y; - copyNextWord(m_buffer, BUFFERSIZE); + copyNextWord(m_buffer, Buffersize); x = (float) fast_atof(m_buffer); - copyNextWord(m_buffer, BUFFERSIZE); + copyNextWord(m_buffer, Buffersize); y = (float) fast_atof(m_buffer); point2d_array.push_back(aiVector2D(x, y)); @@ -306,12 +306,12 @@ void ObjFileParser::getVector2( std::vector &point2d_array ) { // Get values for a new face instance void ObjFileParser::getFace(aiPrimitiveType type) { - copyNextLine(m_buffer, BUFFERSIZE); + copyNextLine(m_buffer, Buffersize); if (m_DataIt == m_DataItEnd) return; char *pPtr = m_buffer; - char *pEnd = &pPtr[BUFFERSIZE]; + char *pEnd = &pPtr[Buffersize]; pPtr = getNextToken(pPtr, pEnd); if (pPtr == pEnd || *pPtr == '\0') return; @@ -468,8 +468,9 @@ void ObjFileParser::getMaterialDesc() // Get next data for material data m_DataIt = getNextToken(m_DataIt, m_DataItEnd); - if (m_DataIt == m_DataItEnd) + if (m_DataIt == m_DataItEnd) { return; + } char *pStart = &(*m_DataIt); while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) { @@ -483,14 +484,11 @@ void ObjFileParser::getMaterialDesc() // Search for material std::map::iterator it = m_pModel->m_MaterialMap.find( strName ); - if ( it == m_pModel->m_MaterialMap.end() ) - { + if ( it == m_pModel->m_MaterialMap.end() ) { // Not found, use default material m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping"); - } - else - { + } else { // Found, using detected material m_pModel->m_pCurrentMaterial = (*it).second; if ( needsNewMesh( strName )) @@ -539,18 +537,26 @@ void ObjFileParser::getMaterialLib() // Check for existence const std::string strMatName(pStart, &(*m_DataIt)); - IOStream *pFile = m_pIO->Open(strMatName); + std::string absName; + if ( m_pIO->StackSize() > 0 ) { + const std::string &path = m_pIO->CurrentDirectory(); + absName = path + strMatName; + } else { + absName = strMatName; + } + //IOStream *pFile = m_pIO->Open( strMatName ); + IOStream *pFile = m_pIO->Open( absName ); if (!pFile ) { - DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName); + DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName ); m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); return; } // Import material library data from file std::vector buffer; - BaseImporter::TextFileToBuffer(pFile,buffer); + BaseImporter::TextFileToBuffer( pFile, buffer ); m_pIO->Close( pFile ); // Importing the material library diff --git a/code/ObjFileParser.h b/code/ObjFileParser.h index 85f555567..66f378f29 100644 --- a/code/ObjFileParser.h +++ b/code/ObjFileParser.h @@ -62,10 +62,9 @@ class IOSystem; /// \class ObjFileParser /// \brief Parser for a obj waveform file -class ObjFileParser -{ +class ObjFileParser { public: - static const size_t BUFFERSIZE = 4096; + static const size_t Buffersize = 4096; typedef std::vector DataArray; typedef std::vector::iterator DataArrayIt; typedef std::vector::const_iterator ConstDataArrayIt; @@ -137,9 +136,10 @@ private: //! Current line (for debugging) unsigned int m_uiLine; //! Helper buffer - char m_buffer[BUFFERSIZE]; + char m_buffer[Buffersize]; /// Pointer to IO system instance. IOSystem *m_pIO; + /// Path to the current model }; } // Namespace Assimp diff --git a/include/assimp/IOSystem.hpp b/include/assimp/IOSystem.hpp index 4b4d55fd4..81b3e910a 100644 --- a/include/assimp/IOSystem.hpp +++ b/include/assimp/IOSystem.hpp @@ -53,6 +53,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #include "types.h" + +#include + namespace Assimp { class IOStream; @@ -170,10 +173,19 @@ public: */ inline bool ComparePaths (const std::string& one, const std::string& second) const; + + virtual bool PushDirectory( const std::string &path ); + virtual const std::string &CurrentDirectory() const; + virtual size_t StackSize() const; + virtual bool PopDirectory(); + +private: + std::vector m_pathStack; }; // ---------------------------------------------------------------------------- -AI_FORCE_INLINE IOSystem::IOSystem() +AI_FORCE_INLINE IOSystem::IOSystem() : + m_pathStack() { // empty } @@ -220,6 +232,43 @@ inline bool IOSystem::ComparePaths (const std::string& one, } // ---------------------------------------------------------------------------- +inline bool IOSystem::PushDirectory( const std::string &path ) { + if ( path.empty() ) { + return false; + } + + m_pathStack.push_back( path ); + + return true; +} + +// ---------------------------------------------------------------------------- +inline const std::string &IOSystem::CurrentDirectory() const { + if ( m_pathStack.empty() ) { + static const std::string Dummy(""); + return Dummy; + } + return m_pathStack[ m_pathStack.size()-1 ]; +} + +// ---------------------------------------------------------------------------- +inline size_t IOSystem::StackSize() const { + return m_pathStack.size(); +} + +// ---------------------------------------------------------------------------- +inline bool IOSystem::PopDirectory() { + if ( m_pathStack.empty() ) { + return false; + } + + m_pathStack.pop_back(); + + return true; +} + +// ---------------------------------------------------------------------------- + } //!ns Assimp #endif //AI_IOSYSTEM_H_INC diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a93bcf91f..d3bd490e8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -24,6 +24,7 @@ SET( TEST_SRCS unit/utGenNormals.cpp unit/utImporter.cpp unit/utImproveCacheLocality.cpp + unit/utIOSystem.cpp unit/utJoinVertices.cpp unit/utLimitBoneWeights.cpp unit/utMaterialSystem.cpp diff --git a/test/unit/utIOSystem.cpp b/test/unit/utIOSystem.cpp new file mode 100644 index 000000000..b44976488 --- /dev/null +++ b/test/unit/utIOSystem.cpp @@ -0,0 +1,94 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2014, 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 +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +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 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +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 +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 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ +#include "UnitTestPCH.h" + +#include + +using namespace std; +using namespace Assimp; + +static const string Sep = "/"; +class TestIOSystem : public IOSystem { +public: + TestIOSystem() : IOSystem() {} + virtual ~TestIOSystem() {} + virtual bool Exists( const char* ) const { + return true; + } + virtual char getOsSeparator() const { + return Sep[ 0 ]; + } + + virtual IOStream* Open(const char* pFile, const char* pMode = "rb") { + return NULL; + } + + virtual void Close( IOStream* pFile) { + // empty + } +}; + +class IOSystemTest : public ::testing::Test { +public: + virtual void SetUp() { pImp = new TestIOSystem(); } + virtual void TearDown() { delete pImp; } + +protected: + TestIOSystem* pImp; +}; + +/* +virtual bool PushDirectory( const std::string &path ); +virtual const std::string &CurrentDirectory() const; +virtual bool PopDirectory(); +*/ + +TEST_F( IOSystemTest, accessDirectoryStackTest ) { + EXPECT_FALSE( pImp->PopDirectory() ); + EXPECT_EQ( 0, pImp->StackSize() ); + EXPECT_FALSE( pImp->PushDirectory( "" ) ); + std::string path = "test/"; + EXPECT_TRUE( pImp->PushDirectory( path ) ); + EXPECT_EQ( 1, pImp->StackSize() ); + EXPECT_EQ( path, pImp->CurrentDirectory() ); + EXPECT_TRUE( pImp->PopDirectory() ); + EXPECT_EQ( 0, pImp->StackSize() ); +}