void CObjMeshParser::parse(shared_ptr<CMesh>& pMesh, const string& strFileName)
{
// usefull to retrieve material files
{
const path filePath(strFileName);
m_branchPath = filePath.branch_path();
}
ifstream ifs(strFileName.c_str(), ios::in|ios::ate);
if (!ifs)
throw(CFileNotFoundException(strFileName));
const int fileSize = ifs.tellg(); // get the file size (we started at the end)...
ifs.seekg (0, ios::beg); // ...then get back to start
if (0 == fileSize)
throw CEmptyFileException();
// explain what's going on
CLogger::get() << "Parsing file \"" << strFileName << "\" (file size = " << fileSize << " bytes)...\n" << flush;
// do a bit of cleaning before adding data in case the mesh was used before.
pMesh->clear();
// and go.
int percent = 10; // progress indicator
while(skipCommentLine(ifs))
{
// show progress for files larger than one Mo
if ((fileSize > 1024*1024) && (100*ifs.tellg()/fileSize >= percent)) {
percent = 100*ifs.tellg()/fileSize;
percent = (percent/10)*10;
CLogger::get() << " " << percent << " % done...\n" << flush;
percent += 10;
}
if (false == processLine(pMesh, ifs))
break;
}
}
bool CObjMeshParser::skipCommentLine(istream& is)
{
char next;
while( is >> std::skipws >> next )
{
is.putback(next);
if ('#' == next)
skipLine(is);
else
return true;
}
return false;
}
bool CObjMeshParser::processLine(shared_ptr<CMesh>& pMesh, istream& is)
{
string ele_id;
float x, y, z;
if (!(is >> ele_id))
return false;
if ("mtllib" == ele_id) {
string strFileName;
is >> strFileName;
parseMtlLib(strFileName);
}
else if ("usemtl" == ele_id) {
string strMtlName;
is >> strMtlName;
map<string, SMaterial>::iterator it = m_materialMap.find(strMtlName);
if (it != m_materialMap.end())
pMesh->setMaterial((*it).second);
else
CLogger::get() << " * Material not found in current mtllib :\"" << strMtlName << "\". Ignoring material.\n";
}
else if ("v" == ele_id) { // vertex data
is >> x >> y >> z;
pMesh->addVertex(SVertex(x, y, z));
}
else if ("vt" == ele_id) { // texture data
is >> x >> y >> z;
is.clear(); // is z (i.e. w) is not available, have to clear error flag.
pMesh->addTextureCoord(SVertex(x, y, z));
}
else if ("vn" == ele_id) { // normal data
is >> x >> y >> z;
if(!is.good()) { // in case it is -1#IND00
x = y = z = 0.0;
is.clear();
skipLine(is);
}
pMesh->addNormal(SVertex(x, y, z));
}
else if ("f" == ele_id) { // face data
// face treatment
// Note: obviously this technique only works for convex polygons with ten verts or less.
int vi[10]; // vertex indices.
int ni[10] = { -1, -1, -1, -1, }; // normal indices.
int ti[10] = { -1, -1, -1, -1, }; // tex indices.
int i = 0;
for (char c; i<10; ++i) {
if(!pMesh->hasTextureCoords() && !pMesh->hasNormals())
is >> vi[i];
else if(!pMesh->hasTextureCoords())
is >> vi[i] >> c >> c >> ni[i];
else if(!pMesh->hasNormals())
is >> vi[i] >> c >> ti[i];
else
is >> vi[i] >> c >> ti[i] >> c >> ni[i];
if(!is.good())
break;
}
// Create the polygon face
SPolygonFace face;
for (int k=0; k < i; ++k)
face.addVertTexNorm(vi[k], ti[k], ni[k]);
pMesh->addFace(face);
is.clear();
}
else
skipLine(is);
return true;
}
Comments