From 3665268aa48b90a4e1da35467ee2eb8dce71191e Mon Sep 17 00:00:00 2001 From: cignoni Date: Thu, 13 Oct 2011 08:02:10 +0000 Subject: [PATCH] Significant refactoring. Cleaned up the non glutesselator code. Quad are split in a simpler way. Support for the qobj format preserved... --- wrap/io_trimesh/import_obj.h | 660 +++++++++++++++++------------------ 1 file changed, 315 insertions(+), 345 deletions(-) diff --git a/wrap/io_trimesh/import_obj.h b/wrap/io_trimesh/import_obj.h index d8f3de56..8f9c93a2 100644 --- a/wrap/io_trimesh/import_obj.h +++ b/wrap/io_trimesh/import_obj.h @@ -52,6 +52,7 @@ template class ImporterOBJ { public: + static int &MRGBLineCount(){static int _MRGBLineCount=0; return _MRGBLineCount;} typedef typename OpenMeshType::VertexPointer VertexPointer; typedef typename OpenMeshType::ScalarType ScalarType; @@ -263,13 +264,13 @@ public: // vertices and faces allocatetion VertexIterator vi = vcg::tri::Allocator::AddVertices(m,oi.numVertices); //FaceIterator fi = Allocator::AddFaces(m,oi.numFaces); - + std::vector vertexColorVector; ObjIndexedFace ff; - char *loadingStr = "Loading"; + const char *loadingStr = "Loading"; while (!stream.eof()) { tokens.clear(); - TokenizeNextLine(stream, tokens); + TokenizeNextLine(stream, tokens,&vertexColorVector); unsigned int numTokens = static_cast(tokens.size()); if (numTokens > 0) @@ -341,30 +342,32 @@ public: numVNormals++; } - else if( (header.compare("f")==0) || (header.compare("q")==0) ) // face + else if( (header.compare("f")==0) || (header.compare("q")==0) ) // face { loadingStr="Face Loading"; - bool QuadFlag = false; // QOBJ format by Silva et al for simply storing quadrangular meshes. - if(header.compare("q")==0) { QuadFlag=true; assert(numTokens == 5); } + bool QuadFlag = false; // QOBJ format by Silva et al for simply storing quadrangular meshes. + if(header.compare("q")==0) { QuadFlag=true; assert(numTokens == 5); } - if (numTokens < 4) return E_LESS_THAN_3VERTINFACE; - int vertexesPerFace = static_cast(tokens.size()-1); + if (numTokens < 4) return E_LESS_THAN_3VERTINFACE; + int vertexesPerFace = static_cast(tokens.size()-1); - if( (vertexesPerFace>3) && OpenMeshType::FaceType::HasPolyInfo() ){ - //_BEGIN___ if you are loading a GENERIC POLYGON mesh - ff.set(vertexesPerFace); - for(int i=0;i3) && OpenMeshType::FaceType::HasPolyInfo() ) + { +//_BEGIN___ if you are loading a GENERIC POLYGON mesh + ff.set(vertexesPerFace); + for(int i=0;i > polygonVect(1); // it is a vector of polygon loops polygonVect[0].resize(vertexesPerFace); std::vector indexVVect(vertexesPerFace); @@ -408,12 +411,24 @@ public: for(int pi=0;pi(polygonVect, indexTriangulatedVect); + if(vertexesPerFace<5) + InternalFanTessellator(polygonVect, indexTriangulatedVect); + else + { +#ifdef __gl_h_ + //qDebug("OK: using opengl tessellation for a polygon of %i verteces",vertexesPerFace); + vcg::glu_tesselator::tesselate(polygonVect, indexTriangulatedVect); +#else + //qDebug("Warning: using fan tessellation for a polygon of %i verteces",vertexesPerFace); + InternalFanTessellator(polygonVect, indexTriangulatedVect); +#endif + } extraTriangles+=((indexTriangulatedVect.size()/3) -1); #ifdef QT_VERSION if( int(indexTriangulatedVect.size()/3) != vertexesPerFace-2) @@ -428,28 +443,23 @@ public: for(size_t pi=0;pi3) ff.edge[2]=true; - ++numTriangles; - indexedFaces.push_back(ff); - /* - // A face polygon composed of more than three vertices is triangulated - // according to the following schema: - // v5 - // / \ - // / \ - // / \ - // v1------v4 - // |\ / - // | \ / - // | \ / - // v2---v3 - // - // As shown above, the 5 vertices polygon (v1,v2,v3,v4,v5) - // has been split into the triangles (v1,v2,v3), (v1,v3,v4) e (v1,v4,v5). - // This way vertex v1 becomes the common vertex of all newly generated - // triangles, and this may lead to the creation of very thin triangles. - */ - - int iVertex = 3; - while (iVertex < vertexesPerFace) // add other triangles - { - oi.mask |= Mask::IOM_BITPOLYGONAL; - ObjIndexedFace ffNew=ff; - int v4_index; - int vt4_index; - int vn4_index; - - SplitToken(tokens[++iVertex], v4_index, vn4_index, vt4_index, inputMask); - if(QuadFlag) { v4_index+=1; } - if(!GoodObjIndex(v4_index, numVertices)) - return E_BAD_VERT_INDEX; - - // assigning wedge texture coordinates - // ----------------------------------- - if( oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ) - { - // verifying validity of texture coords index - // ------------------------------------------ - if(!GoodObjIndex(vt4_index,oi.numTexCoords)) - return E_BAD_VERT_TEX_INDEX; - - if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) - if(!GoodObjIndex(vn4_index,numVNormals)) - return E_BAD_VERT_NORMAL_INDEX; - - ffNew.t[1]=ff.t[2]; - ffNew.t[2]=vt4_index; - } - - if ((ff.v[0] == v4_index) || (ff.v[2] == v4_index)) result = E_VERTICES_WITH_SAME_IDX_IN_FACE; - ffNew.v[1]=ff.v[2]; - ffNew.v[2]=v4_index; - - // assigning face normal - // --------------------- - if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) - { - ffNew.n[1]=ff.n[2]; - ffNew.n[2]=vn4_index; - } - // Setting internal edges: edge 1 (the opposite to vertex 0) is always an external edge. - ffNew.edge[0]=true; - ffNew.edge[1]=false; - if(iVertex < vertexesPerFace) ffNew.edge[2]=true; - else ffNew.edge[2]=false; - ++numTriangles; - ++extraTriangles; - indexedFaces.push_back(ffNew); - ff.v[2] = v4_index; - } - }//_END___ if you are loading a TRIMESH mesh -#endif } else if (header.compare("mtllib")==0) // material library { @@ -639,67 +533,74 @@ public: FaceIterator fi = vcg::tri::Allocator::AddFaces(m,numTriangles); //------------------------------------------------------------------------------- - // Now the final pass to convert indexes into pointers for face to vert/norm/tex references - for(int i=0; iT().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 (((oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) != 0) && (m.HasPerFaceColor())) - { - m.face[i].C() = indexedFaces[i].c; - } - - if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) != 0) && (m.HasPerWedgeNormal())) - { - // 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 - { - // computing face normal from position of face vertices - if (m.HasPerFaceNormal()) - { - face::ComputeNormalizedNormal(m.face[i]); - } - } + if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) != 0) && (m.HasPerWedgeTexCoord())) + { + 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]]); - return result; + 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 (((oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) != 0) && (m.HasPerFaceColor())) + { + m.face[i].C() = indexedFaces[i].c; + } + + if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) != 0) && (m.HasPerWedgeNormal())) + { + // 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 + { + // computing face normal from position of face vertices + if (m.HasPerFaceNormal()) + { + face::ComputeNormalizedNormal(m.face[i]); + } + } + } + // 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) + inline static void TokenizeNextLine(std::ifstream &stream, std::vector< std::string > &tokens, std::vector *colVec) { - if(stream.eof()) return; - std::string line; - do - std::getline(stream, line); - while ((line[0] == '#' || line.length()==0) && !stream.eof()); // skip comments and empty lines - - if ((line[0] == '#') || (line.length() == 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 + if(stream.eof()) return; + std::string line; + do + { + std::getline(stream, line); + if(colVec && line[0] == '#') { - 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; - } + // 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(line[1] == 'M' && line[2] == 'R' && line[3] == 'G' && line[4] == 'B') + { // Parsing the polycolor of ZBrush + MRGBLineCount()++; + size_t len = line.length(); + char buf[3]="00"; + Color4b cc(Color4b::Black); + for(int i=6;(i+7)push_back(cc); + } + } } - while (from 0) { @@ -1076,6 +1013,39 @@ public: return true; } + // A face polygon composed of more than three vertices is triangulated + // according to the following schema: + // v5 + // / \ + // / \ + // / \ + // v1------v4 + // |\ / + // | \ / + // | \ / + // v2---v3 + // + // As shown above, the 5 vertices polygon (v1,v2,v3,v4,v5) + // has been split into the triangles (v1,v2,v3), (v1,v3,v4) e (v1,v4,v5). + // This way vertex v1 becomes the common vertex of all newly generated + // triangles, and this may lead to the creation of very thin triangles. + // + // This function is intended as a trivial fallback when glutessellator is not available. + // it assumes just ONE outline + static void InternalFanTessellator(const std::vector< std::vector > & outlines, std::vector & indices) + { + indices.clear(); + if(outlines.empty()) return; + const std::vector &points=outlines[0]; + + for(int i=0;i