From 6a31fa64baa844fff902f221cff187e59dde1f58 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 6 Apr 2018 14:03:39 +1000 Subject: [PATCH 1/3] Refactored ReprojectBorder and added MergeAlongEdges Function --- vcg/complex/algorithms/polygonal_algorithms.h | 218 +++++++++++++++--- 1 file changed, 190 insertions(+), 28 deletions(-) diff --git a/vcg/complex/algorithms/polygonal_algorithms.h b/vcg/complex/algorithms/polygonal_algorithms.h index e699cd40..a839af28 100644 --- a/vcg/complex/algorithms/polygonal_algorithms.h +++ b/vcg/complex/algorithms/polygonal_algorithms.h @@ -471,6 +471,41 @@ public: } } + template + static void ReprojectBorder(PolyMeshType &poly_m, + TriMeshType &tri_mesh, + bool FixS=true) + { + //then reproject on border + for (size_t i=0;i::max(); + CoordType closPos; + for (size_t j=0;j Seg(P0,P1); + ScalarType testD; + CoordType closTest; + vcg::SegmentPointDistance(Seg,testPos,closTest,testD); + if (testD>minD)continue; + minD=testD; + closPos=closTest; + } + poly_m.vert[i].P()=closPos; + } + } + /*! \brief This function smooth the borders of the polygonal mesh and reproject back to the triangolar one * except the vertices that are considered as corner wrt the angleDeg threshold */ @@ -507,33 +542,34 @@ public: AvVert[i]*(1-Damp); } - //then reproject on border - for (size_t i=0;i::max(); - CoordType closPos; - for (size_t j=0;j::max(); +// CoordType closPos; +// for (size_t j=0;j Seg(P0,P1); - ScalarType testD; - CoordType closTest; - vcg::SegmentPointDistance(Seg,testPos,closTest,testD); - if (testD>minD)continue; - minD=testD; - closPos=closTest; - } - poly_m.vert[i].P()=closPos; - } +// CoordType P0,P1; +// P0.Import(tri_mesh.face[j].cP0(k)); +// P1.Import(tri_mesh.face[j].cP1(k)); +// vcg::Segment3 Seg(P0,P1); +// ScalarType testD; +// CoordType closTest; +// vcg::SegmentPointDistance(Seg,testPos,closTest,testD); +// if (testD>minD)continue; +// minD=testD; +// closPos=closTest; +// } +// poly_m.vert[i].P()=closPos; +// } + ReprojectBorder(poly_m,tri_mesh); } } @@ -797,6 +833,47 @@ public: vcg::PolygonalAlgorithm::SmoothReprojectPCA(poly_m,GuideSurf,relaxStep,fixIrr,Damp,SharpDeg,WeightByQuality); } + static void Reproject(PolyMeshType &poly_m, + PolyMeshType &target) + { + vcg::tri::UpdateTopology::FaceFace(poly_m); + vcg::tri::UpdateFlags::VertexBorderFromFaceAdj(poly_m); + + //transform into triangular + TempMesh GuideSurf; + //vcg::tri::PolygonSupport:(GuideSurf,poly_m); + TriangulateToTriMesh(target,GuideSurf); + vcg::tri::UpdateBounding::Box(GuideSurf); + vcg::tri::UpdateNormal::PerVertexNormalizedPerFace(GuideSurf); + vcg::tri::UpdateTopology::FaceFace(GuideSurf); + vcg::tri::UpdateFlags::FaceBorderFromFF(GuideSurf); + + //initialize the grid + typedef typename TempMesh::FaceType FaceType; + typedef vcg::GridStaticPtr TriMeshGrid; + TriMeshGrid grid; + grid.Set(GuideSurf.face.begin(),GuideSurf.face.end()); + + ScalarType MaxD=GuideSurf.bbox.Diag(); + + for (size_t i=0;i=0); + assert(StartI NewV; + for (size_t i=0;iVN(); + ReorderFaceVert(*f1,FirstV1); + + std::vector NewV; + for (size_t i=0;i<(f.VN()-1);i++) + NewV.push_back(f.V(i)); + + for (size_t i=0;i<(f1->VN()-1);i++) + NewV.push_back(f1->V(i)); + + f.Dealloc(); + f.Alloc(NewV.size()); + for (size_t i=0;i::DeleteFace(poly_m,*f1); + } + + static void MergeAlongEdges(PolyMeshType &poly_m, + const std::vector &PolyF, + const std::vector &EdgeI) + { + //create a table with all edges that have to be merged + std::set > NeedMerge; + for (size_t i=0;iP0(EdgeI[i]); + CoordType P1=PolyF[i]->P1(EdgeI[i]); + std::pair key(std::min(P0,P1),std::max(P0,P1)); + NeedMerge.insert(key); + } + + //then cycle and collapse + do{ + for (size_t i=0;i key(std::min(P0,P1),std::max(P0,P1)); + if (NeedMerge.count(key)==0)continue; + + //do the merge + MergeAlongEdge(poly_m,poly_m.face[i],j); + //remove it + NeedMerge.erase(key); + break; + } + } + vcg::tri::Allocator::CompactEveryVector(poly_m); + }while (!NeedMerge.empty()); + } static void Triangulate(PolyMeshType &poly_m) { From 95a2c621044accf148e5e07cd3bc4c129cc5f0de Mon Sep 17 00:00:00 2001 From: Paolo Cignoni Date: Fri, 6 Apr 2018 10:33:53 +0200 Subject: [PATCH 2/3] Refactored a bit the obj importer to remove bug caused by meshes with and without textures --- wrap/io_trimesh/import_obj.h | 2109 +++++++++++++++++----------------- 1 file changed, 1039 insertions(+), 1070 deletions(-) diff --git a/wrap/io_trimesh/import_obj.h b/wrap/io_trimesh/import_obj.h index 9a924dc8..9f9fa909 100644 --- a/wrap/io_trimesh/import_obj.h +++ b/wrap/io_trimesh/import_obj.h @@ -41,1087 +41,1056 @@ namespace vcg { - namespace tri { - namespace io { +namespace tri { +namespace io { - /** - This class encapsulate a filter for importing obj (Alias Wavefront) meshes. - Warning: this code assume little endian (PC) architecture!!! - */ - template - class ImporterOBJ +/** +This class encapsulate a filter for importing obj (Alias Wavefront) meshes. +Warning: this code assume little endian (PC) architecture!!! +*/ + +template +class ImporterOBJ +{ +public: + static int &MRGBLineCount(){static int _MRGBLineCount=0; return _MRGBLineCount;} + + typedef typename OpenMeshType::VertexPointer VertexPointer; + typedef typename OpenMeshType::ScalarType ScalarType; + typedef typename OpenMeshType::VertexType VertexType; + typedef typename OpenMeshType::EdgeType EdgeType; + typedef typename OpenMeshType::FaceType FaceType; + typedef typename OpenMeshType::VertexIterator VertexIterator; + typedef typename OpenMeshType::FaceIterator FaceIterator; + typedef typename OpenMeshType::CoordType CoordType; + + class Info + { + public: + + Info() {} + + /// It returns a bit mask describing the field present in the obj file + int mask=0; + + /// a Simple callback that can be used for long obj parsing. + CallBackPos *cb=nullptr; + + int numVertices; + int numEdges; + int numFaces; // Note that numFaces can be different from the final number of triangles + int numTexCoords=0; + int numNormals; + + }; // end class + + + struct ObjIndexedFace + { + void set(const int & num){v.resize(num);n.resize(num); t.resize(num);} + std::vector v; + std::vector n; + std::vector t; + int tInd; + bool edge[3];// useless if the face is a polygon, no need to have variable length array + Color4b c; + int mInd; + }; + + struct ObjEdge + { + int v0; + int v1; + }; + + struct ObjTexCoord + { + float u; + float v; + }; + + enum OBJError { + // Successfull opening + E_NOERROR = 0*2+0, // A*2+B (A position of correspondig string in the array, B=1 if not critical) + + // Non Critical Errors (only odd numbers) + E_NON_CRITICAL_ERROR = 0*2+1, + E_MATERIAL_FILE_NOT_FOUND = 1*2+1, + E_MATERIAL_NOT_FOUND = 2*2+1, + E_TEXTURE_NOT_FOUND = 3*2+1, + E_VERTICES_WITH_SAME_IDX_IN_FACE = 4*2+1, + E_LESS_THAN_3_VERT_IN_FACE = 5*2+1, + + // Critical Opening Errors (only even numbers) + E_CANTOPEN = 6*2+0, + E_UNEXPECTED_EOF = 7*2+0, + E_ABORTED = 8*2+0, + E_NO_VERTEX = 9*2+0, + E_NO_FACE =10*2+0, + E_BAD_VERTEX_STATEMENT =11*2+0, + E_BAD_VERT_TEX_STATEMENT =12*2+0, + E_BAD_VERT_NORMAL_STATEMENT =13*2+0, + E_BAD_VERT_INDEX =14*2+0, + E_BAD_VERT_TEX_INDEX =15*2+0, + E_BAD_VERT_NORMAL_INDEX =16*2+0, + E_LESS_THAN_4_VERT_IN_QUAD =17*2+0 + }; + + // to check if a given error is critical or not. + static bool ErrorCritical(int err) + { + if (err==0) return false; + if (err&1) return false; + return true; + } + + static const char* ErrorMsg(int error) + { + const int MAXST = 18; + static const char* obj_error_msg[MAXST] = + { + /* 0 */ "No errors", + + /* 1 */ "Material library file wrong or not found, a default white material is used", + /* 2 */ "Some materials definitions were not found, a default white material is used where no material was available", + /* 3 */ "Texture file not found", + /* 4 */ "Identical vertex indices found in the same faces -- faces ignored", + /* 5 */ "Faces with fewer than 3 vertices -- faces ignored", + + /* 6 */ "Can't open file", + /* 7 */ "Premature End of File. File truncated?", + /* 8 */ "Loading aborted by user", + /* 9 */ "No vertex found", + /* 10 */ "No face found", + /* 11 */ "Vertex statement with fewer than 3 coords", + /* 12 */ "Texture coords statement with fewer than 2 coords", + /* 13 */ "Vertex normal statement with fewer than 3 coords", + /* 14 */ "Bad vertex index in face", + /* 15 */ "Bad texture coords index in face", + /* 16 */ "Bad vertex normal index in face", + /* 17 */ "Quad faces with number of corners different from 4" + }; + + error >>= 1; + + if( (error>=MAXST) || (error<0) ) return "Unknown error"; + else return obj_error_msg[error]; + } + + // Helper functions that checks the range of indexes + // putting them in the correct range if less than zero (as in the obj style) + + static bool GoodObjIndex(int &index, const int maxVal) + { + if (index > maxVal) return false; + if (index < 0) + { + index += maxVal+1; + if (index<0 || index > maxVal) return false; + } + return true; + } + + static int Open(OpenMeshType &mesh, const char *filename, int &loadmask, CallBackPos *cb=0) + { + Info oi; + oi.mask=0; + oi.cb=cb; + int ret=Open(mesh,filename,oi); + loadmask=oi.mask; + return ret; + } + + /*! + * Opens an object file (in ascii format) and populates the mesh passed as first + * accordingly to read data + * \param m The mesh model to be populated with data stored into the file + * \param filename The name of the file to be opened + * \param oi A structure containing infos about the object to be opened + */ + static int Open( OpenMeshType &m, const char * filename, Info &oi) + { + int result = E_NOERROR; + + m.Clear(); + CallBackPos *cb = oi.cb; + + // if LoadMask has not been called yet, we call it here + if (oi.mask == 0) + LoadMask(filename, oi); + + const int inputMask = oi.mask; + Mask::ClampMask(m,oi.mask); + + if (oi.numVertices == 0) + return E_NO_VERTEX; + + std::ifstream stream(filename); + if (stream.fail()) + { + stream.close(); + return E_CANTOPEN; + } + + typename OpenMeshType::template PerMeshAttributeHandle > materialsHandle = + vcg::tri::Allocator:: template GetPerMeshAttribute >(m, std::string("materialVector")); + typename OpenMeshType::template PerFaceAttributeHandle mIndHandle = + vcg::tri::Allocator:: template GetPerFaceAttribute(m, std::string("materialIndex")); + std::vector& materials = materialsHandle(); // materials vector + std::vector texCoords; // texture coordinates + std::vector normals; // vertex normals + std::vector indexedFaces; + std::vector< std::string > tokens; + std::string line; + std::string header; + + short currentMaterialIdx = 0; // index of current material into materials vector + Color4b currentColor=Color4b::LightGray; // we declare this outside code block since other + // triangles of this face will share the same color + + Material defaultMaterial; // default material: white + defaultMaterial.index=currentMaterialIdx; + materials.push_back(defaultMaterial); + + int numVertices = 0; // stores the number of vertices been read till now + int numEdges = 0; // stores the number of edges read till now + int numTriangles = 0; // stores the number of faces been read till now + int numTexCoords = 0; // stores the number of texture coordinates been read till now + int numVNormals = 0; // stores the number of vertex normals been read till now + + int numVerticesPlusFaces = oi.numVertices + oi.numFaces; + int extraTriangles=0; + // vertices and faces allocation + VertexIterator vi = vcg::tri::Allocator::AddVertices(m,oi.numVertices); + //FaceIterator fi = Allocator::AddFaces(m,oi.numFaces); + // edges found + std::vector ev; + std::vector vertexColorVector; + ObjIndexedFace ff; + const char *loadingStr = "Loading"; + while (!stream.eof()) + { + tokens.clear(); + TokenizeNextLine(stream, tokens, line, &vertexColorVector); + + unsigned int numTokens = static_cast(tokens.size()); + if (numTokens > 0) + { + header.clear(); + header = tokens[0]; + + // callback invocation, abort loading process if the call returns false + if ((cb !=NULL) && (((numTriangles + numVertices)%100)==0) && !(*cb)((100*(numTriangles + numVertices))/numVerticesPlusFaces, loadingStr)) + { + stream.close(); + return E_ABORTED; + } + if (header.compare("v")==0) // vertex + { + loadingStr="Vertex Loading"; + if (numTokens < 4) + { + stream.close(); + return E_BAD_VERTEX_STATEMENT; + } + (*vi).P()[0] = (ScalarType) atof(tokens[1].c_str()); + (*vi).P()[1] = (ScalarType) atof(tokens[2].c_str()); + (*vi).P()[2] = (ScalarType) atof(tokens[3].c_str()); + ++numVertices; + + // assigning vertex color + // ---------------------- + if (((oi.mask & vcg::tri::io::Mask::IOM_VERTCOLOR) != 0) && (HasPerVertexColor(m))) + { + if(numTokens>=7) { - public: - static int &MRGBLineCount(){static int _MRGBLineCount=0; return _MRGBLineCount;} - - typedef typename OpenMeshType::VertexPointer VertexPointer; - typedef typename OpenMeshType::ScalarType ScalarType; - typedef typename OpenMeshType::VertexType VertexType; - typedef typename OpenMeshType::EdgeType EdgeType; - typedef typename OpenMeshType::FaceType FaceType; - typedef typename OpenMeshType::VertexIterator VertexIterator; - typedef typename OpenMeshType::FaceIterator FaceIterator; - typedef typename OpenMeshType::CoordType CoordType; - - class Info + ScalarType rf(atof(tokens[4].c_str())), gf(atof(tokens[5].c_str())), bf(atof(tokens[6].c_str())); + ScalarType scaling = (rf<=1 && gf<=1 && bf<=1) ? 255. : 1; + + unsigned char r = (unsigned char) ((ScalarType) atof(tokens[4].c_str()) * scaling); + unsigned char g = (unsigned char) ((ScalarType) atof(tokens[5].c_str()) * scaling); + unsigned char b = (unsigned char) ((ScalarType) atof(tokens[6].c_str()) * scaling); + unsigned char alpha = (unsigned char) ((numTokens>=8 ? (ScalarType) atof(tokens[7].c_str()) : 1) * scaling); + (*vi).C() = Color4b(r, g, b, alpha); + } + else + { + (*vi).C() = currentColor; + } + } + + ++vi; // move to next vertex iterator + } + else if (header.compare("vt")==0) // vertex texture coords + { + loadingStr="Vertex Texture Loading"; + + if (numTokens < 3) + { + stream.close(); + return E_BAD_VERT_TEX_STATEMENT; + } + ObjTexCoord t; + t.u = static_cast(atof(tokens[1].c_str())); + t.v = static_cast(atof(tokens[2].c_str())); + texCoords.push_back(t); + + numTexCoords++; + } + else if (header.compare("vn")==0) // vertex normal + { + loadingStr="Vertex Normal Loading"; + + if (numTokens != 4) + { + stream.close(); + return E_BAD_VERT_NORMAL_STATEMENT; + } + CoordType n; + n[0] = (ScalarType) atof(tokens[1].c_str()); + n[1] = (ScalarType) atof(tokens[2].c_str()); + n[2] = (ScalarType) atof(tokens[3].c_str()); + normals.push_back(n); + + numVNormals++; + } + else if ( header.compare("l")==0 ) + { + loadingStr = "Edge Loading"; + + if (numTokens < 3) + { + result = E_LESS_THAN_3_VERT_IN_FACE; // TODO add proper/handling error code + continue; + } + + ObjEdge e = { (atoi(tokens[1].c_str()) - 1), + (atoi(tokens[2].c_str()) - 1) }; + ev.push_back(e); + + numEdges++; + } + else if( (header.compare("f")==0) || (header.compare("q")==0) ) // face + { + loadingStr="Face Loading"; + + int vertexesPerFace = static_cast(tokens.size()-1); + + bool QuadFlag = false; // QOBJ format by Silva et al for simply storing quadrangular meshes. + if(header.compare("q")==0) { + QuadFlag=true; + if (vertexesPerFace != 4) { + stream.close(); + return E_LESS_THAN_4_VERT_IN_QUAD; + } + } + + + if (vertexesPerFace < 3) { + // face with fewer than 3 vertices found: ignore this face + extraTriangles--; + result = E_LESS_THAN_3_VERT_IN_FACE; + continue; + } + + + if( (vertexesPerFace>3) && OpenMeshType::FaceType::HasPolyInfo() ) + { + //_BEGIN___ if you are filling a vcg mesh with GENERIC POLYGON + ff.set(vertexesPerFace); + for(int i=0;i v; - std::vector n; - std::vector t; - int tInd; - bool edge[3];// useless if the face is a polygon, no need to have variable length array - Color4b c; - int mInd; - }; - - struct ObjEdge - { - int v0; - int v1; - }; - - struct ObjTexCoord - { - float u; - float v; - }; - - enum OBJError { - // Successfull opening - E_NOERROR = 0*2+0, // A*2+B (A position of correspondig string in the array, B=1 if not critical) - - // Non Critical Errors (only odd numbers) - E_NON_CRITICAL_ERROR = 0*2+1, - E_MATERIAL_FILE_NOT_FOUND = 1*2+1, - E_MATERIAL_NOT_FOUND = 2*2+1, - E_TEXTURE_NOT_FOUND = 3*2+1, - E_VERTICES_WITH_SAME_IDX_IN_FACE = 4*2+1, - E_LESS_THAN_3_VERT_IN_FACE = 5*2+1, - - // Critical Opening Errors (only even numbers) - E_CANTOPEN = 6*2+0, - E_UNEXPECTED_EOF = 7*2+0, - E_ABORTED = 8*2+0, - E_NO_VERTEX = 9*2+0, - E_NO_FACE =10*2+0, - E_BAD_VERTEX_STATEMENT =11*2+0, - E_BAD_VERT_TEX_STATEMENT =12*2+0, - E_BAD_VERT_NORMAL_STATEMENT =13*2+0, - E_BAD_VERT_INDEX =14*2+0, - E_BAD_VERT_TEX_INDEX =15*2+0, - E_BAD_VERT_NORMAL_INDEX =16*2+0, - E_LESS_THAN_4_VERT_IN_QUAD =17*2+0 - }; - - // to check if a given error is critical or not. - static bool ErrorCritical(int err) - { - if (err==0) return false; - if (err&1) return false; - return true; + stream.close(); + return E_BAD_VERT_TEX_INDEX; } - - static const char* ErrorMsg(int error) + ff.tInd=materials[currentMaterialIdx].index; + } + + // verifying validity of vertex indices + std::vector tmp = ff.v; + std::sort(tmp.begin(),tmp.end()); + std::unique(tmp.begin(),tmp.end()); + if(tmp.size() != ff.v.size()) { + result = E_VERTICES_WITH_SAME_IDX_IN_FACE; + extraTriangles--; + continue; + } + + for(int i=0;i>= 1; - - if( (error>=MAXST) || (error<0) ) return "Unknown error"; - else return obj_error_msg[error]; + stream.close(); + return E_BAD_VERT_NORMAL_INDEX; } - - // Helper functions that checks the range of indexes - // putting them in the correct range if less than zero (as in the obj style) - - static bool GoodObjIndex(int &index, const int maxVal) - { - if (index > maxVal) return false; - if (index < 0) - { - index += maxVal+1; - if (index<0 || index > maxVal) return false; - } - return true; - } - - static int Open(OpenMeshType &mesh, const char *filename, int &loadmask, CallBackPos *cb=0) - { - Info oi; - oi.mask=0; - oi.cb=cb; - int ret=Open(mesh,filename,oi); - loadmask=oi.mask; - return ret; - } - - /*! - * Opens an object file (in ascii format) and populates the mesh passed as first - * accordingly to read data - * \param m The mesh model to be populated with data stored into the file - * \param filename The name of the file to be opened - * \param oi A structure containing infos about the object to be opened - */ - static int Open( OpenMeshType &m, const char * filename, Info &oi) - { - int result = E_NOERROR; - - m.Clear(); - CallBackPos *cb = oi.cb; - - // if LoadMask has not been called yet, we call it here - if (oi.mask == 0) - LoadMask(filename, oi); - - const int inputMask = oi.mask; - Mask::ClampMask(m,oi.mask); - - if (oi.numVertices == 0) - return E_NO_VERTEX; - - // Commented out this test. You should be allowed to load point clouds. - //if (oi.numFaces == 0) - // return E_NO_FACE; - - - std::ifstream stream(filename); - if (stream.fail()) - { - stream.close(); - return E_CANTOPEN; - } - - typename OpenMeshType::template PerMeshAttributeHandle > materialsHandle = - vcg::tri::Allocator:: template GetPerMeshAttribute >(m, std::string("materialVector")); - typename OpenMeshType::template PerFaceAttributeHandle mIndHandle = - vcg::tri::Allocator:: template GetPerFaceAttribute(m, std::string("materialIndex")); - std::vector& materials = materialsHandle(); // materials vector - std::vector texCoords; // texture coordinates - std::vector normals; // vertex normals - std::vector indexedFaces; - std::vector< std::string > tokens; - std::string line; - std::string header; - - short currentMaterialIdx = 0; // index of current material into materials vector - Color4b currentColor=Color4b::LightGray; // we declare this outside code block since other - // triangles of this face will share the same color - - Material defaultMaterial; // default material: white - defaultMaterial.index=currentMaterialIdx; - materials.push_back(defaultMaterial); - - int numVertices = 0; // stores the number of vertices been read till now - int numEdges = 0; // stores the number of edges read till now - int numTriangles = 0; // stores the number of faces been read till now - int numTexCoords = 0; // stores the number of texture coordinates been read till now - int numVNormals = 0; // stores the number of vertex normals been read till now - - int numVerticesPlusFaces = oi.numVertices + oi.numFaces; - int extraTriangles=0; - // vertices and faces allocation - VertexIterator vi = vcg::tri::Allocator::AddVertices(m,oi.numVertices); - //FaceIterator fi = Allocator::AddFaces(m,oi.numFaces); - // edges found - std::vector ev; - std::vector vertexColorVector; - ObjIndexedFace ff; - const char *loadingStr = "Loading"; - while (!stream.eof()) - { - tokens.clear(); - TokenizeNextLine(stream, tokens, line, &vertexColorVector); - - unsigned int numTokens = static_cast(tokens.size()); - if (numTokens > 0) - { - header.clear(); - header = tokens[0]; - - // callback invocation, abort loading process if the call returns false - if ((cb !=NULL) && (((numTriangles + numVertices)%100)==0) && !(*cb)((100*(numTriangles + numVertices))/numVerticesPlusFaces, loadingStr)) - { - stream.close(); - return E_ABORTED; - } - if (header.compare("v")==0) // vertex - { - loadingStr="Vertex Loading"; - if (numTokens < 4) - { - stream.close(); - return E_BAD_VERTEX_STATEMENT; - } - (*vi).P()[0] = (ScalarType) atof(tokens[1].c_str()); - (*vi).P()[1] = (ScalarType) atof(tokens[2].c_str()); - (*vi).P()[2] = (ScalarType) atof(tokens[3].c_str()); - ++numVertices; - - // assigning vertex color - // ---------------------- - if (((oi.mask & vcg::tri::io::Mask::IOM_VERTCOLOR) != 0) && (HasPerVertexColor(m))) - { - if(numTokens>=7) - { - ScalarType rf(atof(tokens[4].c_str())), gf(atof(tokens[5].c_str())), bf(atof(tokens[6].c_str())); - ScalarType scaling = (rf<=1 && gf<=1 && bf<=1) ? 255. : 1; - - unsigned char r = (unsigned char) ((ScalarType) atof(tokens[4].c_str()) * scaling); - unsigned char g = (unsigned char) ((ScalarType) atof(tokens[5].c_str()) * scaling); - unsigned char b = (unsigned char) ((ScalarType) atof(tokens[6].c_str()) * scaling); - unsigned char alpha = (unsigned char) ((numTokens>=8 ? (ScalarType) atof(tokens[7].c_str()) : 1) * scaling); - (*vi).C() = Color4b(r, g, b, alpha); - } - else - { - (*vi).C() = currentColor; - } - } - - ++vi; // move to next vertex iterator - } - else if (header.compare("vt")==0) // vertex texture coords - { - loadingStr="Vertex Texture Loading"; - - if (numTokens < 3) - { - stream.close(); - return E_BAD_VERT_TEX_STATEMENT; - } - ObjTexCoord t; - t.u = static_cast(atof(tokens[1].c_str())); - t.v = static_cast(atof(tokens[2].c_str())); - texCoords.push_back(t); - - numTexCoords++; - } - else if (header.compare("vn")==0) // vertex normal - { - loadingStr="Vertex Normal Loading"; - - if (numTokens != 4) - { - stream.close(); - return E_BAD_VERT_NORMAL_STATEMENT; - } - CoordType n; - n[0] = (ScalarType) atof(tokens[1].c_str()); - n[1] = (ScalarType) atof(tokens[2].c_str()); - n[2] = (ScalarType) atof(tokens[3].c_str()); - normals.push_back(n); - - numVNormals++; - } - else if ( header.compare("l")==0 ) - { - loadingStr = "Edge Loading"; - - if (numTokens < 3) - { - result = E_LESS_THAN_3_VERT_IN_FACE; // TODO add proper/handling error code - continue; - } - - ObjEdge e = { (atoi(tokens[1].c_str()) - 1), - (atoi(tokens[2].c_str()) - 1) }; - ev.push_back(e); - - numEdges++; - } - else if( (header.compare("f")==0) || (header.compare("q")==0) ) // face - { - loadingStr="Face Loading"; - - int vertexesPerFace = static_cast(tokens.size()-1); - - bool QuadFlag = false; // QOBJ format by Silva et al for simply storing quadrangular meshes. - if(header.compare("q")==0) { - QuadFlag=true; - if (vertexesPerFace != 4) { - stream.close(); - return E_LESS_THAN_4_VERT_IN_QUAD; - } - } - - - if (vertexesPerFace < 3) { - // face with fewer than 3 vertices found: ignore this face - extraTriangles--; - result = E_LESS_THAN_3_VERT_IN_FACE; - continue; - } - - - if( (vertexesPerFace>3) && OpenMeshType::FaceType::HasPolyInfo() ) - { - //_BEGIN___ if you are loading a GENERIC POLYGON mesh - ff.set(vertexesPerFace); - for(int i=0;i tmp = ff.v; - std::sort(tmp.begin(),tmp.end()); - std::unique(tmp.begin(),tmp.end()); - if(tmp.size() != ff.v.size()) { - result = E_VERTICES_WITH_SAME_IDX_IN_FACE; - extraTriangles--; - continue; - } - - for(int i=0;i > polygonVect(1); // it is a vector of polygon loops - polygonVect[0].resize(vertexesPerFace); - std::vector indexVVect(vertexesPerFace); - std::vector indexNVect(vertexesPerFace); - std::vector indexTVect(vertexesPerFace); - std::vector indexTriangulatedVect; - - for(int pi=0;pi3) - oi.mask |= Mask::IOM_BITPOLYGONAL; - - if(vertexesPerFace<5) - FanTessellator(polygonVect, indexTriangulatedVect); - else - { + } + + + if( oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) // assigning face color + ff.c = currentColor; + + ++numTriangles; + indexedFaces.push_back(ff); + + //_END ___ if you are filling a vcg mesh with GENERIC POLYGON + } + else + { + //_BEGIN___ if you are filling a vcg mesh with TRIANGLES + std::vector > polygonVect(1); // it is a vector of polygon loops + polygonVect[0].resize(vertexesPerFace); + std::vector indexVVect(vertexesPerFace); + std::vector indexNVect(vertexesPerFace); + std::vector indexTVect(vertexesPerFace); + std::vector indexTriangulatedVect; + + for(int pi=0;pi3) + oi.mask |= Mask::IOM_BITPOLYGONAL; + + if(vertexesPerFace<5) + FanTessellator(polygonVect, indexTriangulatedVect); + else + { #ifdef __gl_h_ - //qDebug("OK: using opengl tessellation for a polygon of %i verteces",vertexesPerFace); - vcg::glu_tesselator::tesselate(polygonVect, indexTriangulatedVect); - if(indexTriangulatedVect.size()==0) - FanTessellator(polygonVect, indexTriangulatedVect); + //qDebug("OK: using opengl tessellation for a polygon of %i verteces",vertexesPerFace); + vcg::glu_tesselator::tesselate(polygonVect, indexTriangulatedVect); + if(indexTriangulatedVect.size()==0) + FanTessellator(polygonVect, indexTriangulatedVect); #else - //qDebug("Warning: using fan tessellation for a polygon of %i verteces",vertexesPerFace); - FanTessellator(polygonVect, indexTriangulatedVect); + //qDebug("Warning: using fan tessellation for a polygon of %i verteces",vertexesPerFace); + FanTessellator(polygonVect, indexTriangulatedVect); #endif - } - extraTriangles+=((indexTriangulatedVect.size()/3) -1); + } + extraTriangles+=((indexTriangulatedVect.size()/3) -1); #ifdef QT_VERSION - if( int(indexTriangulatedVect.size()/3) != vertexesPerFace-2) - { - qDebug("Warning there is a degenerate poligon of %i verteces that was triangulated into %i triangles",vertexesPerFace,int(indexTriangulatedVect.size()/3)); - for(size_t qq=0;qq",tokens[qq].c_str()); - } + if( int(indexTriangulatedVect.size()/3) != vertexesPerFace-2) + { + qDebug("Warning there is a degenerate poligon of %i verteces that was triangulated into %i triangles",vertexesPerFace,int(indexTriangulatedVect.size()/3)); + for(size_t qq=0;qq",tokens[qq].c_str()); + } #endif - //qDebug("Triangulated a face of %i vertexes into %i triangles",polygonVect[0].size(),indexTriangulatedVect.size()); - - for(size_t pi=0;pi 1)) // material library - { - // obtain the name of the file containing materials library - std::string materialFileName; - if (tokens.size() == 2) - materialFileName = tokens[1]; //play it safe - else - materialFileName = line.substr(7); //get everything after "mtllib " - - if (!LoadMaterials( materialFileName.c_str(), materials, m.textures)) - result = E_MATERIAL_FILE_NOT_FOUND; - } - else if ((header.compare("usemtl")==0) && (tokens.size() > 1)) // material usage - { - // emergency check. If there are no materials, the materail library failed to load or was not specified - // but there are tools that save the material library with the same name of the file, but do not add the - // "mtllib" definition in the header. So, we can try to see if this is the case - if ((materials.size() == 1)&&(materials[0].materialName == "")){ - std::string materialFileName(filename); - materialFileName.replace(materialFileName.end()-4, materialFileName.end(), ".mtl"); - LoadMaterials(materialFileName.c_str(), materials, m.textures); - } - - std::string materialName; - if (tokens.size() == 2) - materialName = tokens[1]; //play it safe - else - materialName = line.substr(7); //get everything after "usemtl " - - bool found = false; - unsigned i = 0; - while (!found && (i < materials.size())) - { - std::string currentMaterialName = materials[i].materialName; - if (currentMaterialName == materialName) - { - currentMaterialIdx = i; - Material &material = materials[currentMaterialIdx]; - Point3f diffuseColor = material.Kd; - unsigned char r = (unsigned char) (diffuseColor[0] * 255.0); - unsigned char g = (unsigned char) (diffuseColor[1] * 255.0); - unsigned char b = (unsigned char) (diffuseColor[2] * 255.0); - unsigned char alpha = (unsigned char) (material.Tr * 255.0); - currentColor= Color4b(r, g, b, alpha); - found = true; - } - ++i; - } - - if (!found) - { - currentMaterialIdx = 0; - result = E_MATERIAL_NOT_FOUND; - } - } - // we simply ignore other situations - } // end for each line... - } // end while stream not eof - assert((numTriangles +numVertices) == numVerticesPlusFaces+extraTriangles); - vcg::tri::Allocator::AddFaces(m,numTriangles); - - // Add found edges - if (numEdges > 0) - { - vcg::tri::Allocator::AddEdges(m,numEdges); - - assert(m.edge.size() == size_t(m.en)); - - for(int i=0; i= 0 && size_t(e.v0) < m.vert.size() && - e.v1 >= 0 && size_t(e.v1) < m.vert.size()); - // TODO add proper handling of bad indices - m.edge[i].V(0) = &(m.vert[e.v0]); - m.edge[i].V(1) = &(m.vert[e.v1]); - } - } - //------------------------------------------------------------------------------- - - // Now the final passes: - // First Pass to convert indexes into pointers for face to vert/norm/tex references - for(int i=0; i=0 && vertInd < m.vn); (void)vertInd; - m.face[i].V(j) = &(m.vert[indexedFaces[i].v[j]]); - - if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) != 0) && (HasPerWedgeTexCoord(m))) - { - ObjTexCoord t = texCoords[indexedFaces[i].t[j]]; - m.face[i].WT(j).u() = t.u; - m.face[i].WT(j).v() = t.v; - m.face[i].WT(j).n() = indexedFaces[i].tInd; - } - if ( oi.mask & vcg::tri::io::Mask::IOM_VERTTEXCOORD ) { - ObjTexCoord t = texCoords[indexedFaces[i].t[j]]; - m.face[i].V(j)->T().u() = t.u; - m.face[i].V(j)->T().v() = t.v; - m.face[i].V(j)->T().n() = indexedFaces[i].tInd; - } - if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) - { - m.face[i].WN(j).Import(normals[indexedFaces[i].n[j]]); - } - - if ( oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL ) - { - m.face[i].V(j)->N().Import(normals[indexedFaces[i].n[j]]); - } - - // set faux edge flags according to internals faces - if (indexedFaces[i].edge[j]) - m.face[i].SetF(j); - else - m.face[i].ClearF(j); - } - - if (HasPerFaceNormal(m)) - { - if (((oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) != 0) && (HasPerFaceColor(m))) - { - m.face[i].C() = indexedFaces[i].c; - mIndHandle[i] = indexedFaces[i].mInd; - } - - if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) != 0) && (HasPerWedgeNormal(m))) - { - // face normal is computed as an average of wedge normals - m.face[i].N().Import(m.face[i].WN(0)+m.face[i].WN(1)+m.face[i].WN(2)); - } - else - { - m.face[i].N().Import(TriangleNormal(m.face[i]).Normalize()); - } - } - } - // final pass to manage the ZBrush PerVertex Color that are managed into comments - if(vertexColorVector.size()>0) - { - // if(vertexColorVector.size()!=m.vn){ - // qDebug("Warning Read %i vertices and %i vertex colors",m.vn,vertexColorVector.size()); - // qDebug("line count %i x 64 = %i",MRGBLineCount(), MRGBLineCount()*64); - // } - for(int i=0;i &tokens, std::string &line, std::vector *colVec) - { - if(stream.eof()) return; - - do - { - std::getline(stream, line); - // We have to manage backspace terminated lines, - // joining them together before parsing them - if(!line.empty() && line.back()==13) line.pop_back(); - while(!line.empty() && line.back()=='\\') { - std::string tmpLine; - std::getline(stream, tmpLine); - if(tmpLine.back()==13) line.pop_back(); - line.pop_back(); - line.append(tmpLine); - } - const size_t len = line.length(); - if((len > 0) && colVec && line[0] == '#') - { - // The following MRGB block contains ZBrush Vertex Color (Polypaint) - // and masking output as 4 hexadecimal values per vertex. The vertex color format is MMRRGGBB with up to 64 entries per MRGB line. - if((len >= 5) && line[1] == 'M' && line[2] == 'R' && line[3] == 'G' && line[4] == 'B') - { // Parsing the polycolor of ZBrush - MRGBLineCount()++; - char buf[3]="00"; - Color4b cc(Color4b::Black); - for(size_t i=6;(i+7)push_back(cc); - } - } - } - } - while (( line.length()==0 || line[0] == '#') && !stream.eof()); // skip comments and empty lines - - if ( (line.length() == 0)||(line[0] == '#') ) // can be true only on last line of file - return; - - size_t from = 0; - size_t to = 0; - size_t length = line.size(); - - tokens.clear(); - do - { - while (from!=length && (line[from]==' ' || line[from]=='\t' || line[from]=='\r') ) - from++; - if(from!=length) - { - to = from+1; - while (to!=length && line[to]!=' ' && line[to] != '\t' && line[to]!='\r') - to++; - tokens.push_back(line.substr(from, to-from).c_str()); - from = to; - } - } - while (from2) - { - if(line[0]=='v') - { - if ((line[1] == ' ') || (line[1] == '\t')) - { - oi.numVertices++; - if (firstV) - { - int sepN = 0; - for (size_t lit = 0; lit < line.size(); lit++){ - if ((line[lit] == ' ') || (line[lit] == '\t')) - sepN++; - } - if (sepN >= 6) - bHasPerVertexColor = true; - firstV = false; - } - } - if(line[1]=='t') oi.numTexCoords++; - if(line[1]=='n') { - oi.numNormals ++; - bHasNormals = true; - } - } - else { - if((line[0]=='f') || (line[0]=='q')) oi.numFaces++; - else - if (line[0]=='l') oi.numEdges++; - else - if(line[0]=='u' && line[1]=='s') bHasPerFaceColor = true; // there is a usematerial so add per face color - } - } - } - oi.mask = 0; - if (oi.numTexCoords) - { - if (oi.numTexCoords==oi.numVertices) - oi.mask |= vcg::tri::io::Mask::IOM_VERTTEXCOORD; - - oi.mask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD; - // Usually if you have tex coords you also have materials - oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR; - } - if(bHasPerFaceColor) oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR; - if(bHasPerVertexColor) oi.mask |= vcg::tri::io::Mask::IOM_VERTCOLOR; - if (bHasNormals) { - if (oi.numNormals == oi.numVertices) - oi.mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; - else - oi.mask |= vcg::tri::io::Mask::IOM_WEDGNORMAL; - } - if (oi.numEdges) - oi.mask |= vcg::tri::io::Mask::IOM_EDGEINDEX; - - stream.close(); - - return true; - } - - static bool LoadMask(const char * filename, int &mask) - { - Info oi; - bool ret=LoadMask(filename, oi); - mask= oi.mask; - return ret; - } - - static bool LoadMaterials(const char * filename, std::vector &materials, std::vector &textures) - { - // assumes we are in the right directory - - std::ifstream stream(filename); - if (stream.fail()) - return false; - - std::vector< std::string > tokens; - std::string line; - std::string header; - - materials.clear(); - Material currentMaterial; - - // Fill in some default values for the material - currentMaterial.index = (unsigned int)(-1); - currentMaterial.Ka = Point3f(0.2, 0.2, 0.2); - currentMaterial.Kd = Point3f(1, 1, 1); - currentMaterial.Ks = Point3f(1, 1, 1); - currentMaterial.Tr = 1; - currentMaterial.Ns = 0; - currentMaterial.illum = 2; - - bool first = true; - while (!stream.eof()) - { - tokens.clear(); - TokenizeNextLine(stream, tokens, line, 0); - - if (tokens.size() > 0) - { - header.clear(); - header = tokens[0]; - - if (header.compare("newmtl")==0) - { - if (!first) - { - materials.push_back(currentMaterial); - currentMaterial = Material(); - currentMaterial.index = (unsigned int)(-1); - } - else - first = false; - //strcpy(currentMaterial.name, tokens[1].c_str()); - if(tokens.size() < 2) - return false; - else if (tokens.size() == 2) - currentMaterial.materialName = tokens[1]; //play it safe - else - currentMaterial.materialName = line.substr(7); //space in the name, get everything after "newmtl " - } - else if (header.compare("Ka")==0) - { - if (tokens.size() < 4) - return false; - float r = (float) atof(tokens[1].c_str()); - float g = (float) atof(tokens[2].c_str()); - float b = (float) atof(tokens[3].c_str()); - - currentMaterial.Ka = Point3f(r, g, b); - } - else if (header.compare("Kd")==0) - { - if (tokens.size() < 4) - return false; - float r = (float) atof(tokens[1].c_str()); - float g = (float) atof(tokens[2].c_str()); - float b = (float) atof(tokens[3].c_str()); - - currentMaterial.Kd = Point3f(r, g, b); - } - else if (header.compare("Ks")==0) - { - if (tokens.size() < 4) - return false; - float r = (float) atof(tokens[1].c_str()); - float g = (float) atof(tokens[2].c_str()); - float b = (float) atof(tokens[3].c_str()); - - currentMaterial.Ks = Point3f(r, g, b); - } - else if ( (header.compare("d")==0) || - (header.compare("Tr")==0) ) // alpha - { - if (tokens.size() < 2) - return false; - currentMaterial.Tr = (float) atof(tokens[1].c_str()); - } - else if (header.compare("Ns")==0) // shininess - { - if (tokens.size() < 2) - return false; - currentMaterial.Ns = float(atoi(tokens[1].c_str())); - } - else if (header.compare("illum")==0) // specular illumination on/off - { - if (tokens.size() < 2) - return false; - int illumination = atoi(tokens[1].c_str()); - //currentMaterial.bSpecular = (illumination == 2); - currentMaterial.illum = illumination; - } - else if(header.compare("map_Kd")==0) // texture name - { - std::string textureName; - if (tokens.size() < 2) - return false; - else if (tokens.size() == 2) - textureName = tokens[1]; //play it safe - else - textureName = line.substr(7); //get everything after "map_Kd " - - currentMaterial.map_Kd=textureName; - - // adding texture name into textures vector (if not already present) - // avoid adding the same name twice - bool found = false; - unsigned int size = static_cast(textures.size()); - unsigned j = 0; - while (!found && (j < size)) - { - if (textureName.compare(textures[j])==0) - { - currentMaterial.index = (int)j; - found = true; - } - ++j; - } - if (!found) - { - textures.push_back(textureName); - currentMaterial.index = (int)size; - } - } - // we simply ignore other situations - } - } - materials.push_back(currentMaterial); // add last read material - - stream.close(); - - return true; - } - - }; // end class - } // end Namespace tri - } // end Namespace io + //qDebug("Triangulated a face of %i vertexes into %i triangles",polygonVect[0].size(),indexTriangulatedVect.size()); + + for(size_t pi=0;pi 1)) // material library + { + // obtain the name of the file containing materials library + std::string materialFileName; + if (tokens.size() == 2) + materialFileName = tokens[1]; //play it safe + else + materialFileName = line.substr(7); //get everything after "mtllib " + + if (!LoadMaterials( materialFileName.c_str(), materials, m.textures)) + result = E_MATERIAL_FILE_NOT_FOUND; + } + else if ((header.compare("usemtl")==0) && (tokens.size() > 1)) // material usage + { + // emergency check. If there are no materials, the material library failed to load or was not specified + // but there are tools that save the material library with the same name of the file, but do not add the + // "mtllib" definition in the header. So, we can try to see if this is the case + if ((materials.size() == 1)&&(materials[0].materialName == "")){ + std::string materialFileName(filename); + materialFileName.replace(materialFileName.end()-4, materialFileName.end(), ".mtl"); + LoadMaterials(materialFileName.c_str(), materials, m.textures); + } + + std::string materialName; + if (tokens.size() == 2) + materialName = tokens[1]; //play it safe + else + materialName = line.substr(7); //get everything after "usemtl " + + bool found = false; + unsigned i = 0; + while (!found && (i < materials.size())) + { + std::string currentMaterialName = materials[i].materialName; + if (currentMaterialName == materialName) + { + currentMaterialIdx = i; + Material &material = materials[currentMaterialIdx]; + Point3f diffuseColor = material.Kd; + unsigned char r = (unsigned char) (diffuseColor[0] * 255.0); + unsigned char g = (unsigned char) (diffuseColor[1] * 255.0); + unsigned char b = (unsigned char) (diffuseColor[2] * 255.0); + unsigned char alpha = (unsigned char) (material.Tr * 255.0); + currentColor= Color4b(r, g, b, alpha); + found = true; + } + ++i; + } + + if (!found) + { + currentMaterialIdx = 0; + result = E_MATERIAL_NOT_FOUND; + } + } + // we simply ignore other situations + } // end for each line... + } // end while stream not eof + assert((numTriangles +numVertices) == numVerticesPlusFaces+extraTriangles); + vcg::tri::Allocator::AddFaces(m,numTriangles); + + // Add found edges + if (numEdges > 0) + { + vcg::tri::Allocator::AddEdges(m,numEdges); + + assert(m.edge.size() == size_t(m.en)); + + for(int i=0; i= 0 && size_t(e.v0) < m.vert.size() && + e.v1 >= 0 && size_t(e.v1) < m.vert.size()); + // TODO add proper handling of bad indices + m.edge[i].V(0) = &(m.vert[e.v0]); + m.edge[i].V(1) = &(m.vert[e.v1]); + } + } + //------------------------------------------------------------------------------- + + // Now the final passes: + // First Pass to convert indexes into pointers for face to vert/norm/tex references + for(int i=0; i=0 && vertInd < m.vn); (void)vertInd; + m.face[i].V(j) = &(m.vert[indexedFaces[i].v[j]]); + + if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) != 0) && (HasPerWedgeTexCoord(m))) + { + ObjTexCoord t = texCoords[indexedFaces[i].t[j]]; + m.face[i].WT(j).u() = t.u; + m.face[i].WT(j).v() = t.v; + m.face[i].WT(j).n() = indexedFaces[i].tInd; + } + if ( oi.mask & vcg::tri::io::Mask::IOM_VERTTEXCOORD ) { + ObjTexCoord t = texCoords[indexedFaces[i].t[j]]; + m.face[i].V(j)->T().u() = t.u; + m.face[i].V(j)->T().v() = t.v; + m.face[i].V(j)->T().n() = indexedFaces[i].tInd; + } + if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) + { + m.face[i].WN(j).Import(normals[indexedFaces[i].n[j]]); + } + + if ( oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL ) + { + m.face[i].V(j)->N().Import(normals[indexedFaces[i].n[j]]); + } + + // set faux edge flags according to internals faces + if (indexedFaces[i].edge[j]) + m.face[i].SetF(j); + else + m.face[i].ClearF(j); + } + + if (HasPerFaceNormal(m)) + { + if (((oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) != 0) && (HasPerFaceColor(m))) + { + m.face[i].C() = indexedFaces[i].c; + mIndHandle[i] = indexedFaces[i].mInd; + } + + if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) != 0) && (HasPerWedgeNormal(m))) + { + // face normal is computed as an average of wedge normals + m.face[i].N().Import(m.face[i].WN(0)+m.face[i].WN(1)+m.face[i].WN(2)); + } + else + { + m.face[i].N().Import(TriangleNormal(m.face[i]).Normalize()); + } + } + } + // final pass to manage the ZBrush PerVertex Color that are managed into comments + if(vertexColorVector.size()>0) + { + // if(vertexColorVector.size()!=m.vn){ + // qDebug("Warning Read %i vertices and %i vertex colors",m.vn,vertexColorVector.size()); + // qDebug("line count %i x 64 = %i",MRGBLineCount(), MRGBLineCount()*64); + // } + for(int i=0;i &tokens, std::string &line, std::vector *colVec) + { + if(stream.eof()) return; + + do + { + std::getline(stream, line); + // We have to manage backspace terminated lines, + // joining them together before parsing them + if(!line.empty() && line.back()==13) line.pop_back(); + while(!line.empty() && line.back()=='\\') { + std::string tmpLine; + std::getline(stream, tmpLine); + if(tmpLine.back()==13) line.pop_back(); + line.pop_back(); + line.append(tmpLine); + } + const size_t len = line.length(); + if((len > 0) && colVec && line[0] == '#') + { + // The following MRGB block contains ZBrush Vertex Color (Polypaint) + // and masking output as 4 hexadecimal values per vertex. The vertex color format is MMRRGGBB with up to 64 entries per MRGB line. + if((len >= 5) && line[1] == 'M' && line[2] == 'R' && line[3] == 'G' && line[4] == 'B') + { // Parsing the polycolor of ZBrush + MRGBLineCount()++; + char buf[3]="00"; + Color4b cc(Color4b::Black); + for(size_t i=6;(i+7)push_back(cc); + } + } + } + } + while (( line.length()==0 || line[0] == '#') && !stream.eof()); // skip comments and empty lines + + if ( (line.length() == 0)||(line[0] == '#') ) // can be true only on last line of file + return; + + size_t from = 0; + size_t to = 0; + size_t length = line.size(); + + tokens.clear(); + do + { + while (from!=length && (line[from]==' ' || line[from]=='\t' || line[from]=='\r') ) + from++; + if(from!=length) + { + to = from+1; + while (to!=length && line[to]!=' ' && line[to] != '\t' && line[to]!='\r') + to++; + tokens.push_back(line.substr(from, to-from).c_str()); + from = to; + } + } + while (from &tokens, int pos) + { + float r = (float) atof(tokens[pos+0].c_str()); + float g = (float) atof(tokens[pos+1].c_str()); + float b = (float) atof(tokens[pos+2].c_str()); + return Point3f(r, g, b); + } + + /*! + * Retrieves infos about kind of data stored into the file and fills a mask appropriately + * \param filename The name of the file to open + * \param mask A mask which will be filled according to type of data found in the object + * \param oi A structure which will be filled with infos about the object to be opened + */ + + static bool LoadMask(const char * filename, Info &oi) + { + + std::ifstream stream(filename); + if (stream.fail()) + { + stream.close(); + return false; + } + // obtain length of file: + stream.seekg (0, std::ios::end); + int length = stream.tellg(); + stream.seekg (0, std::ios::beg); + + if (length == 0) return false; + + bool bHasPerFaceColor = false; + bool bHasNormals = false; + bool bHasPerVertexColor = false; + + oi.numVertices=0; + oi.numEdges=0; + oi.numFaces=0; + oi.numTexCoords=0; + oi.numNormals=0; + int lineCount=0; + int totRead=0; + bool firstV = true; + std::string line; + while (!stream.eof()) + { + lineCount++; + std::getline(stream, line); + totRead+=line.size(); + if(oi.cb && (lineCount%1000)==0) + (*oi.cb)( (int)(100.0*(float(totRead))/float(length)), "Loading mask..."); + if(line.size()>2) + { + if(line[0]=='v') + { + if ((line[1] == ' ') || (line[1] == '\t')) + { + oi.numVertices++; + if (firstV) + { + int sepN = 0; + for (size_t lit = 0; lit < line.size(); lit++){ + if ((line[lit] == ' ') || (line[lit] == '\t')) + sepN++; + } + if (sepN >= 6) + bHasPerVertexColor = true; + firstV = false; + } + } + if(line[1]=='t') oi.numTexCoords++; + if(line[1]=='n') { + oi.numNormals ++; + bHasNormals = true; + } + } + else { + if((line[0]=='f') || (line[0]=='q')) oi.numFaces++; + else + if (line[0]=='l') oi.numEdges++; + else + if(line[0]=='u' && line[1]=='s') bHasPerFaceColor = true; // there is a usematerial so add per face color + } + } + } + oi.mask = 0; + if (oi.numTexCoords) + { + if (oi.numTexCoords==oi.numVertices) + oi.mask |= vcg::tri::io::Mask::IOM_VERTTEXCOORD; + + oi.mask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD; + // Usually if you have tex coords you also have materials + oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR; + } + if(bHasPerFaceColor) oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR; + if(bHasPerVertexColor) oi.mask |= vcg::tri::io::Mask::IOM_VERTCOLOR; + if (bHasNormals) { + if (oi.numNormals == oi.numVertices) + oi.mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; + else + oi.mask |= vcg::tri::io::Mask::IOM_WEDGNORMAL; + } + if (oi.numEdges) + oi.mask |= vcg::tri::io::Mask::IOM_EDGEINDEX; + + stream.close(); + + return true; + } + + static bool LoadMask(const char * filename, int &mask) + { + Info oi; + bool ret=LoadMask(filename, oi); + mask= oi.mask; + return ret; + } + + static bool LoadMaterials(const char * filename, std::vector &materials, std::vector &textures) + { + // assumes we are in the right directory + + std::ifstream stream(filename); + if (stream.fail()) + return false; + + std::vector< std::string > tokens; + std::string line; + std::string header; + + materials.clear(); + Material currentMaterial; + + // Fill in some default values for the material + currentMaterial.index = (unsigned int)(-1); + currentMaterial.Ka = Point3f(0.2, 0.2, 0.2); + currentMaterial.Kd = Point3f(1, 1, 1); + currentMaterial.Ks = Point3f(1, 1, 1); + currentMaterial.Tr = 1; + currentMaterial.Ns = 0; + currentMaterial.illum = 2; + + bool first = true; + while (!stream.eof()) + { + tokens.clear(); + TokenizeNextLine(stream, tokens, line, 0); + + if (tokens.size() > 0) + { + header.clear(); + header = tokens[0]; + + if (header.compare("newmtl")==0) + { + if (!first) + { + materials.push_back(currentMaterial); + currentMaterial = Material(); + currentMaterial.index = (unsigned int)(-1); + } + else + first = false; + //strcpy(currentMaterial.name, tokens[1].c_str()); + if(tokens.size() < 2) + return false; + else if (tokens.size() == 2) + currentMaterial.materialName = tokens[1]; //play it safe + else + currentMaterial.materialName = line.substr(7); //space in the name, get everything after "newmtl " + } + else if (header.compare("Ka")==0) + { + if (tokens.size() < 4) return false; + currentMaterial.Ka = Point3fFrom3Tokens(tokens,1); + } + else if (header.compare("Kd")==0) + { + if (tokens.size() < 4) return false; + currentMaterial.Kd = Point3fFrom3Tokens(tokens,1); + } + else if (header.compare("Ks")==0) + { + if (tokens.size() < 4) return false; + currentMaterial.Ks = Point3fFrom3Tokens(tokens,1); + } + else if ( (header.compare("d")==0) || + (header.compare("Tr")==0) ) // alpha + { + if (tokens.size() < 2) return false; + currentMaterial.Tr = (float) atof(tokens[1].c_str()); + } + else if (header.compare("Ns")==0) // shininess + { + if (tokens.size() < 2) return false; + currentMaterial.Ns = float(atoi(tokens[1].c_str())); + } + else if (header.compare("illum")==0) // specular illumination on/off + { + if (tokens.size() < 2) return false; + currentMaterial.illum = atoi(tokens[1].c_str());; + } + else if(header.compare("map_Kd")==0) // texture name + { + std::string textureName; + if (tokens.size() < 2) + return false; + else if (tokens.size() == 2) + textureName = tokens[1]; //play it safe + else + textureName = line.substr(7); //get everything after "map_Kd " + + currentMaterial.map_Kd=textureName; + + // adding texture name into textures vector (if not already present) + // avoid adding the same name twice + auto it = std::find(textures.begin(), textures.end(), textureName); + if(it==textures.end()) { + currentMaterial.index = textures.size(); + textures.push_back(textureName); + } else { + currentMaterial.index = std::distance(textures.begin(),it); + } + } + // we simply ignore other situations + } + } + materials.push_back(currentMaterial); // add last read material + + stream.close(); + // Sometimes some materials have texture and no texture + // in this case for sake of uniformity we just use the first texture. + if(!textures.empty()) + { + for(size_t i=0;i Date: Fri, 6 Apr 2018 11:00:28 +0200 Subject: [PATCH 3/3] Added yet another variant of ply ushort/char combination... close meshlab bug #290 --- wrap/io_trimesh/import_ply.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wrap/io_trimesh/import_ply.h b/wrap/io_trimesh/import_ply.h index abff74c1..dfb030d3 100644 --- a/wrap/io_trimesh/import_ply.h +++ b/wrap/io_trimesh/import_ply.h @@ -221,10 +221,10 @@ static const PropDescriptor &FaceDesc(int i) /* 15 */ {"face", "vertex_indices", ply::T_UINT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_UCHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, /* 16 */ {"face", "vertex_indices", ply::T_UINT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_CHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, /* 17 */ {"face", "vertex_indices", ply::T_UINT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_INT, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, -/* 18 */ {"face", "vertex_indices", ply::T_SHORT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_CHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, -/* 19 */ {"face", "vertex_indices", ply::T_SHORT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_UCHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, -/* 20 */ {"face", "vertex_indices", ply::T_SHORT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_INT, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, -/* 21 */ {"face", "vertex_indices", ply::T_CHAR, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_UCHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0} +/* 18 */ {"face", "vertex_indices", ply::T_UINT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_USHORT,ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, +/* 19 */ {"face", "vertex_indices", ply::T_SHORT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_CHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, +/* 20 */ {"face", "vertex_indices", ply::T_SHORT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_UCHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, +/* 21 */ {"face", "vertex_indices", ply::T_SHORT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_INT, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, }; return qf[i]; }