diff --git a/code/ColladaExporter.cpp b/code/ColladaExporter.cpp index 19f86fcf8..8fba4bf74 100644 --- a/code/ColladaExporter.cpp +++ b/code/ColladaExporter.cpp @@ -235,9 +235,13 @@ void ColladaExporter::WriteMaterials() if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS ) name = "mat"; materials[a].name = std::string( "m") + boost::lexical_cast (a) + name.C_Str(); - for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) - if( !isalnum( *it) ) + for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) { + // isalnum on MSVC asserts for code points in [0,255]. Thus prevent unwanted promotion + // of char to signed int and take the unsigned char value. + if( !isalnum( static_cast(*it) ) ) { *it = '_'; + } + } ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT); if( !materials[a].ambient.texture.empty() ) numTextures++; diff --git a/code/ObjExporter.cpp b/code/ObjExporter.cpp index 9ac902ee3..b680abb74 100644 --- a/code/ObjExporter.cpp +++ b/code/ObjExporter.cpp @@ -61,14 +61,14 @@ void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene boost::scoped_ptr outfile (pIOSystem->Open(pFile,"wt")); if(outfile == NULL) { throw DeadlyExportError("could not open output .obj file: " + std::string(pFile)); - } + } outfile->Write( exporter.mOutput.str().c_str(), static_cast(exporter.mOutput.tellp()),1); } { boost::scoped_ptr outfile (pIOSystem->Open(exporter.GetMaterialLibFileName(),"wt")); if(outfile == NULL) { throw DeadlyExportError("could not open output .mtl file: " + std::string(exporter.GetMaterialLibFileName())); - } + } outfile->Write( exporter.mOutputMat.str().c_str(), static_cast(exporter.mOutputMat.tellp()),1); } } @@ -199,6 +199,7 @@ void ObjExporter :: WriteGeometryFile() AddNode(pScene->mRootNode,mBase); // write vertex positions + vpMap.getVectors(vp); mOutput << "# " << vp.size() << " vertex positions" << endl; BOOST_FOREACH(const aiVector3D& v, vp) { mOutput << "v " << v.x << " " << v.y << " " << v.z << endl; @@ -206,6 +207,7 @@ void ObjExporter :: WriteGeometryFile() mOutput << endl; // write uv coordinates + vtMap.getVectors(vt); mOutput << "# " << vt.size() << " UV coordinates" << endl; BOOST_FOREACH(const aiVector3D& v, vt) { mOutput << "vt " << v.x << " " << v.y << " " << v.z << endl; @@ -213,6 +215,7 @@ void ObjExporter :: WriteGeometryFile() mOutput << endl; // write vertex normals + vnMap.getVectors(vn); mOutput << "# " << vn.size() << " vertex normals" << endl; BOOST_FOREACH(const aiVector3D& v, vn) { mOutput << "vn " << v.x << " " << v.y << " " << v.z << endl; @@ -252,6 +255,31 @@ void ObjExporter :: WriteGeometryFile() } } + + + + +int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec) +{ + vecIndexMap::dataType::iterator vertIt = vecMap.find(vec); + if(vertIt != vecMap.end()){// vertex already exists, so reference it + return vertIt->second; + } + vecMap[vec] = mNextIndex; + int ret = mNextIndex; + mNextIndex++; + return ret; +} + +void ObjExporter::vecIndexMap::getVectors( std::vector& vecs ) +{ + vecs.resize(vecMap.size()); + for(vecIndexMap::dataType::iterator it = vecMap.begin(); it != vecMap.end(); it++){ + vecs[it->second-1] = it->first; + } +} + + // ------------------------------------------------------------------------------------------------ void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) { @@ -262,6 +290,7 @@ void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatri mesh.matname = GetMaterialName(m->mMaterialIndex); mesh.faces.resize(m->mNumFaces); + for(unsigned int i = 0; i < m->mNumFaces; ++i) { const aiFace& f = m->mFaces[i]; @@ -281,21 +310,22 @@ void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatri for(unsigned int a = 0; a < f.mNumIndices; ++a) { const unsigned int idx = f.mIndices[a]; - // XXX need a way to check if this is an unique vertex or if we had it already, - // in which case we should instead reference the previous occurrence. - ai_assert(m->mVertices); - vp.push_back( mat * m->mVertices[idx] ); - face.indices[a].vp = vp.size(); + aiVector3D vert = mat * m->mVertices[idx]; + face.indices[a].vp = vpMap.getIndex(vert); if (m->mNormals) { - vn.push_back( m->mNormals[idx] ); + face.indices[a].vn = vnMap.getIndex(m->mNormals[idx]); + } + else{ + face.indices[a].vn = 0; } - face.indices[a].vn = vn.size(); if (m->mTextureCoords[0]) { - vt.push_back( m->mTextureCoords[0][idx] ); + face.indices[a].vt = vtMap.getIndex(m->mTextureCoords[0][idx]); + } + else{ + face.indices[a].vt = 0; } - face.indices[a].vt = vt.size(); } } } diff --git a/code/ObjExporter.h b/code/ObjExporter.h index f857f5879..4f6555aa5 100644 --- a/code/ObjExporter.h +++ b/code/ObjExporter.h @@ -112,6 +112,36 @@ private: const aiScene* const pScene; std::vector vp, vn, vt; + + + struct aiVectorCompare + { + bool operator() (const aiVector3D& a, const aiVector3D& b) const + { + if(a.x < b.x) return true; + if(a.x > b.x) return false; + if(a.y < b.y) return true; + if(a.y > b.y) return false; + if(a.z < b.z) return true; + return false; + } + }; + + class vecIndexMap + { + int mNextIndex; + typedef std::map dataType; + dataType vecMap; + public: + + vecIndexMap():mNextIndex(1) + {} + + int getIndex(const aiVector3D& vec); + void getVectors( std::vector& vecs ); + }; + + vecIndexMap vpMap, vnMap, vtMap; std::vector meshes; // this endl() doesn't flush() the stream diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index ab8fdd124..e701ddc62 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -112,7 +112,7 @@ void ObjFileParser::parseFile() case 'v': // Parse a vertex texture coordinate { ++m_DataIt; - if (*m_DataIt == ' ') + if (*m_DataIt == ' ' || *m_DataIt == '\t') { // Read in vertex definition getVector3(m_pModel->m_Vertices); @@ -290,6 +290,10 @@ void ObjFileParser::getFace(aiPrimitiveType type) std::vector *pNormalID = new std::vector; bool hasNormal = false; + const int vSize = m_pModel->m_Vertices.size(); + const int vtSize = m_pModel->m_TextureCoord.size(); + const int vnSize = m_pModel->m_Normals.size(); + const bool vt = (!m_pModel->m_TextureCoord.empty()); const bool vn = (!m_pModel->m_Normals.empty()); int iStep = 0, iPos = 0; @@ -323,7 +327,11 @@ void ObjFileParser::getFace(aiPrimitiveType type) { //OBJ USES 1 Base ARRAYS!!!! const int iVal = atoi( pPtr ); + + // increment iStep position based off of the sign and # of digits int tmp = iVal; + if (iVal < 0) + ++iStep; while ( ( tmp = tmp / 10 )!=0 ) ++iStep; @@ -348,6 +356,27 @@ void ObjFileParser::getFace(aiPrimitiveType type) reportErrorTokenInFace(); } } + else if ( iVal < 0 ) + { + // Store relatively index + if ( 0 == iPos ) + { + pIndices->push_back( vSize + iVal ); + } + else if ( 1 == iPos ) + { + pTexID->push_back( vtSize + iVal ); + } + else if ( 2 == iPos ) + { + pNormalID->push_back( vnSize + iVal ); + hasNormal = true; + } + else + { + reportErrorTokenInFace(); + } + } } pPtr += iStep; } diff --git a/code/STLLoader.cpp b/code/STLLoader.cpp index fff58d04a..39c6ac9cd 100644 --- a/code/STLLoader.cpp +++ b/code/STLLoader.cpp @@ -86,7 +86,12 @@ bool IsAsciiSTL(const char* buffer, unsigned int fileSize) { if (IsBinarySTL(buffer, fileSize)) return false; - if (fileSize < 5) + const char* bufferEnd = buffer + fileSize; + + if (!SkipSpaces(&buffer)) + return false; + + if (buffer + 5 >= bufferEnd) return false; return strncmp(buffer, "solid", 5) == 0; @@ -209,7 +214,11 @@ void STLImporter::LoadASCIIFile() { aiMesh* pMesh = pScene->mMeshes[0]; - const char* sz = mBuffer + 5; // skip the "solid" + const char* sz = mBuffer; + SkipSpaces(&sz); + ai_assert(!IsLineEnd(sz)); + + sz += 5; // skip the "solid" SkipSpaces(&sz); const char* szMe = sz; while (!::IsSpaceOrNewLine(*sz)) {