From 303d4e1fca9e41a9ce95bdbc6c2254f54459a333 Mon Sep 17 00:00:00 2001 From: cignoni Date: Mon, 25 Nov 2013 12:49:12 +0000 Subject: [PATCH] factored out the internal fan tessellator from the obj to a generic place to be used also in other importers --- wrap/io_trimesh/import_obj.h | 1996 +++++++++++++------------- wrap/io_trimesh/import_off.h | 1281 +++++++++-------- wrap/io_trimesh/io_fan_tessellator.h | 71 + 3 files changed, 1692 insertions(+), 1656 deletions(-) create mode 100644 wrap/io_trimesh/io_fan_tessellator.h diff --git a/wrap/io_trimesh/import_obj.h b/wrap/io_trimesh/import_obj.h index 6abea947..0b767f85 100644 --- a/wrap/io_trimesh/import_obj.h +++ b/wrap/io_trimesh/import_obj.h @@ -25,10 +25,10 @@ #ifndef __VCGLIB_IMPORT_OBJ #define __VCGLIB_IMPORT_OBJ -#include #include #include #include +#include #ifdef __gl_h_ #include #endif @@ -41,1098 +41,1064 @@ namespace vcg { - 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 - { - 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::FaceType FaceType; - typedef typename OpenMeshType::VertexIterator VertexIterator; - typedef typename OpenMeshType::FaceIterator FaceIterator; - typedef typename OpenMeshType::CoordType CoordType; - - class Info - { - public: - - Info() - { - mask = 0; - cb = 0; - numTexCoords=0; - } - - /// It returns a bit mask describing the field preesnt in the ply file - int mask; - - /// a Simple callback that can be used for long obj parsing. - // it returns the current position, and formats a string with a description of what th efunction is doing (loading vertexes, faces...) - CallBackPos *cb; - - /// number of vertices - int numVertices; - /// number of faces (the number of triangles could be - /// larger in presence of polygonal faces - int numFaces; - /// number of texture coords indexes - int numTexCoords; - /// number of normals - int numNormals; - - }; // end class - - - //struct OBJFacet - //{ - // CoordType n; - // CoordType t; - // CoordType v[3]; - // - // short attr; // material index - //}; - 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; - }; - - 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=-1; - 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 == -1) - 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()) - return E_CANTOPEN; - - std::vector materials; // materials vector - std::vector texCoords; // texture coordinates - std::vector normals; // vertex normals - std::vector indexedFaces; - std::vector< std::string > tokens; - 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 - materials.push_back(defaultMaterial); - - int numVertices = 0; // stores the number of vertices been 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 allocatetion - VertexIterator vi = vcg::tri::Allocator::AddVertices(m,oi.numVertices); - //FaceIterator fi = Allocator::AddFaces(m,oi.numFaces); - std::vector vertexColorVector; - ObjIndexedFace ff; - const char *loadingStr = "Loading"; - while (!stream.eof()) - { - tokens.clear(); - TokenizeNextLine(stream, tokens,&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)) - return E_ABORTED; - - if (header.compare("v")==0) // vertex - { - loadingStr="Vertex Loading"; - if (numTokens < 4) 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) 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) 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("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) { - 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) - InternalFanTessellator(polygonVect, indexTriangulatedVect); - else - { + 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 + { + 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::FaceType FaceType; + typedef typename OpenMeshType::VertexIterator VertexIterator; + typedef typename OpenMeshType::FaceIterator FaceIterator; + typedef typename OpenMeshType::CoordType CoordType; + + class Info + { + public: + + Info() + { + mask = 0; + cb = 0; + numTexCoords=0; + } + + /// It returns a bit mask describing the field preesnt in the ply file + int mask; + + /// a Simple callback that can be used for long obj parsing. + // it returns the current position, and formats a string with a description of what th efunction is doing (loading vertexes, faces...) + CallBackPos *cb; + + /// number of vertices + int numVertices; + /// number of faces (the number of triangles could be + /// larger in presence of polygonal faces + int numFaces; + /// number of texture coords indexes + int numTexCoords; + /// number of normals + int numNormals; + + }; // end class + + + //struct OBJFacet + //{ + // CoordType n; + // CoordType t; + // CoordType v[3]; + // + // short attr; // material index + //}; + 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; + }; + + 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=-1; + 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 == -1) + 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()) + return E_CANTOPEN; + + std::vector materials; // materials vector + std::vector texCoords; // texture coordinates + std::vector normals; // vertex normals + std::vector indexedFaces; + std::vector< std::string > tokens; + 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 + materials.push_back(defaultMaterial); + + int numVertices = 0; // stores the number of vertices been 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 allocatetion + VertexIterator vi = vcg::tri::Allocator::AddVertices(m,oi.numVertices); + //FaceIterator fi = Allocator::AddFaces(m,oi.numFaces); + std::vector vertexColorVector; + ObjIndexedFace ff; + const char *loadingStr = "Loading"; + while (!stream.eof()) + { + tokens.clear(); + TokenizeNextLine(stream, tokens,&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)) + return E_ABORTED; + + if (header.compare("v")==0) // vertex + { + loadingStr="Vertex Loading"; + if (numTokens < 4) 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) 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) 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("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) { + 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 + { #ifdef __gl_h_ - //qDebug("OK: using opengl tessellation for a polygon of %i verteces",vertexesPerFace); - vcg::glu_tesselator::tesselate(polygonVect, indexTriangulatedVect); + //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); + //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()); + //qDebug("Triangulated a face of %i vertexes into %i triangles",polygonVect[0].size(),indexTriangulatedVect.size()); - for(size_t pi=0;pi::AddFaces(m,numTriangles); - //------------------------------------------------------------------------------- + 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); + //------------------------------------------------------------------------------- - // Now the final passes: - // First 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_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 ) - { + if ( oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL ) + { // qDebug("XXXXXX %i",indexedFaces[i].n[j]); - m.face[i].V(j)->N().Import(normals[indexedFaces[i].n[j]]); - } + 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); - } + // 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; - } + if (HasPerFaceNormal(m)) + { + if (((oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) != 0) && (HasPerFaceColor(m))) + { + m.face[i].C() = indexedFaces[i].c; + } - 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 - { - 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;i0) + { + // 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::vector *colVec) - { - if(stream.eof()) return; - std::string line; - do - { - std::getline(stream, line); - 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 + /*! + * Read the next valid line and parses it into "tokens", allowing + * the tokens to be read one at a time. + * \param stream The object providing the input stream + * \param tokens The "tokens" in the next line + */ + 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); + 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; + 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(); + 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 %i %i %i",token.c_str(),vId,nId,tId); - /* - const std::string vStr = (hasPosition) ? (token.substr(0, firstSep)) : ("0"); - const std::string tStr = (hasTexcoord) ? (token.substr(firstSep + 1, secondSep - firstSep - 1)) : ("0"); - const std::string nStr = (hasNormal) ? (token.substr(secondSep + 1)) : ("0"); + /* + const std::string vStr = (hasPosition) ? (token.substr(0, firstSep)) : ("0"); + const std::string tStr = (hasTexcoord) ? (token.substr(firstSep + 1, secondSep - firstSep - 1)) : ("0"); + const std::string nStr = (hasNormal) ? (token.substr(secondSep + 1)) : ("0"); - if (!vStr.empty()) vId = atoi(vStr.c_str()) - 1; - if (!tStr.empty()) tId = atoi(tStr.c_str()) - 1; - if (!nStr.empty()) nId = atoi(nStr.c_str()) - 1; - */ - } + if (!vStr.empty()) vId = atoi(vStr.c_str()) - 1; + if (!tStr.empty()) tId = atoi(tStr.c_str()) - 1; + if (!nStr.empty()) nId = atoi(nStr.c_str()) - 1; + */ + } #if 0 - // This function takes a token and, according to the mask, it returns the indexes of the involved vertex, normal and texcoord indexes. - // Example. if the obj file has vertex texcoord (e.g. lines 'vt 0.444 0.5555') - // when parsing a line like - // f 46/303 619/325 624/326 623/327 - // if in the mask you have specified to read wedge tex coord - // for the first token it will return inside vId and tId the corresponding indexes 46 and 303 ) - inline static void SplitToken(std::string token, int &vId, int &nId, int &tId, int mask) - { - std::string vertex; - std::string texcoord; - std::string normal; + // This function takes a token and, according to the mask, it returns the indexes of the involved vertex, normal and texcoord indexes. + // Example. if the obj file has vertex texcoord (e.g. lines 'vt 0.444 0.5555') + // when parsing a line like + // f 46/303 619/325 624/326 623/327 + // if in the mask you have specified to read wedge tex coord + // for the first token it will return inside vId and tId the corresponding indexes 46 and 303 ) + inline static void SplitToken(std::string token, int &vId, int &nId, int &tId, int mask) + { + std::string vertex; + std::string texcoord; + std::string normal; - if( ( mask & Mask::IOM_WEDGTEXCOORD ) && (mask & Mask::IOM_WEDGNORMAL) ) SplitVVTVNToken(token, vertex, texcoord, normal); - if(!( mask & Mask::IOM_WEDGTEXCOORD ) && (mask & Mask::IOM_WEDGNORMAL) ) SplitVVNToken(token, vertex, normal); - if( ( mask & Mask::IOM_WEDGTEXCOORD ) &&!(mask & Mask::IOM_WEDGNORMAL) ) SplitVVTToken(token, vertex, texcoord); - if(!( mask & Mask::IOM_WEDGTEXCOORD ) &&!(mask & Mask::IOM_WEDGNORMAL) ) SplitVToken(token, vertex); + if( ( mask & Mask::IOM_WEDGTEXCOORD ) && (mask & Mask::IOM_WEDGNORMAL) ) SplitVVTVNToken(token, vertex, texcoord, normal); + if(!( mask & Mask::IOM_WEDGTEXCOORD ) && (mask & Mask::IOM_WEDGNORMAL) ) SplitVVNToken(token, vertex, normal); + if( ( mask & Mask::IOM_WEDGTEXCOORD ) &&!(mask & Mask::IOM_WEDGNORMAL) ) SplitVVTToken(token, vertex, texcoord); + if(!( mask & Mask::IOM_WEDGTEXCOORD ) &&!(mask & Mask::IOM_WEDGNORMAL) ) SplitVToken(token, vertex); - vId = atoi(vertex.c_str()) - 1; - if(mask & Mask::IOM_WEDGTEXCOORD) tId = atoi(texcoord.c_str()) - 1; - if(mask & Mask::IOM_WEDGNORMAL) nId = atoi(normal.c_str()) - 1; - } + vId = atoi(vertex.c_str()) - 1; + if(mask & Mask::IOM_WEDGTEXCOORD) tId = atoi(texcoord.c_str()) - 1; + if(mask & Mask::IOM_WEDGNORMAL) nId = atoi(normal.c_str()) - 1; + } - inline static void SplitVToken(std::string token, std::string &vertex) - { - vertex = token; - } + inline static void SplitVToken(std::string token, std::string &vertex) + { + vertex = token; + } - inline static void SplitVVTToken(std::string token, std::string &vertex, std::string &texcoord) - { - vertex.clear(); - texcoord.clear(); + inline static void SplitVVTToken(std::string token, std::string &vertex, std::string &texcoord) + { + vertex.clear(); + texcoord.clear(); - size_t from = 0; - size_t to = 0; - size_t length = token.size(); + size_t from = 0; + size_t to = 0; + size_t length = token.size(); - if(from!=length) - { - char c = token[from]; - vertex.push_back(c); + if(from!=length) + { + char c = token[from]; + vertex.push_back(c); - to = from+1; - while (to2) - { - if(line[0]=='v') - { - if(line[1]==' ') - { - oi.numVertices++; - if(line.size()>=7) - bHasPerVertexColor = true; - } - 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]=='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.numVertices=0; + oi.numFaces=0; + oi.numTexCoords=0; + oi.numNormals=0; + int lineCount=0; + int totRead=0; + 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]==' ') + { + oi.numVertices++; + if(line.size()>=7) + bHasPerVertexColor = true; + } + 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]=='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; - } + 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; + } - return true; - } + return true; + } - static bool LoadMask(const char * filename, int &mask) - { - Info oi; - bool ret=LoadMask(filename, oi); - mask= oi.mask; - return ret; - } + 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 + 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::ifstream stream(filename); + if (stream.fail()) + return false; - std::vector< std::string > tokens; - std::string header; + std::vector< std::string > tokens; + std::string header; - materials.clear(); - Material currentMaterial; - currentMaterial.index = (unsigned int)(-1); + materials.clear(); + Material currentMaterial; + currentMaterial.index = (unsigned int)(-1); - bool first = true; - while (!stream.eof()) - { - tokens.clear(); - TokenizeNextLine(stream, tokens,0); + bool first = true; + while (!stream.eof()) + { + tokens.clear(); + TokenizeNextLine(stream, tokens,0); - if (tokens.size() > 0) - { - header.clear(); - header = tokens[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; - currentMaterial.materialName=tokens[1]; - } - 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()); + 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; + currentMaterial.materialName=tokens[1]; + } + 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.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.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) || (header.compare("map_Ka")==0) ) // texture name - { - if (tokens.size() < 2) - return false; - std::string textureName = tokens[1]; - //strcpy(currentMaterial.textureFileName, textureName.c_str()); - currentMaterial.map_Kd=textureName; + 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) || (header.compare("map_Ka")==0) ) // texture name + { + if (tokens.size() < 2) + return false; + std::string textureName = tokens[1]; + //strcpy(currentMaterial.textureFileName, textureName.c_str()); + 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 + // 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(); + stream.close(); - 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]; + return true; + } - for(size_t i=0;i #include #include -#include - +#include namespace vcg { - namespace tri - { - namespace io - { - // /** \addtogroup */ - // /* @{ */ - /** - This class encapsulate a filter for importing OFF meshes. - A basic description of the OFF file format can be found at http://www.geomview.org/docs/html/geomview_41.html - */ - template - class ImporterOFF - { - public: + namespace tri + { + namespace io + { + // /** \addtogroup */ + // /* @{ */ + /** + This class encapsulate a filter for importing OFF meshes. + A basic description of the OFF file format can be found at http://www.geomview.org/docs/html/geomview_41.html + */ + template + class ImporterOFF + { + public: - typedef typename MESH_TYPE::VertexType VertexType; - typedef typename MESH_TYPE::VertexIterator VertexIterator; - typedef typename MESH_TYPE::VertexPointer VertexPointer; - typedef typename MESH_TYPE::FaceType FaceType; - typedef typename MESH_TYPE::FaceIterator FaceIterator; - typedef typename MESH_TYPE::FacePointer FacePointer; - typedef typename MESH_TYPE::CoordType CoordType; - typedef typename MESH_TYPE::ScalarType ScalarType; + typedef typename MESH_TYPE::VertexType VertexType; + typedef typename MESH_TYPE::VertexIterator VertexIterator; + typedef typename MESH_TYPE::VertexPointer VertexPointer; + typedef typename MESH_TYPE::FaceType FaceType; + typedef typename MESH_TYPE::FaceIterator FaceIterator; + typedef typename MESH_TYPE::FacePointer FacePointer; + typedef typename MESH_TYPE::CoordType CoordType; + typedef typename MESH_TYPE::ScalarType ScalarType; - // OFF codes - enum OFFCodes {NoError=0, CantOpen, InvalidFile, - InvalidFile_MissingOFF, - UnsupportedFormat, ErrorNotTriangularFace,ErrorHighDimension,ErrorDegenerateFace}; + // OFF codes + enum OFFCodes {NoError=0, CantOpen, InvalidFile, + InvalidFile_MissingOFF, + UnsupportedFormat, ErrorNotTriangularFace,ErrorHighDimension,ErrorDegenerateFace}; - /*! - * Standard call for knowing the meaning of an error code - * \param message_code The code returned by Open - * \return The string describing the error code - */ - static const char* ErrorMsg(int message_code) - { - static const char* error_msg[] = - { - "No errors", "Can't open file", "Invalid file", - "Invalid file: OFF file should have in the first line the OFF keyword as a first token", - "Unsupported format", "Face with more than 3 vertices","File with high dimensional vertexes are not supported", "Error Degenerate Face with less than 3 vertices" }; + /*! + * Standard call for knowing the meaning of an error code + * \param message_code The code returned by Open + * \return The string describing the error code + */ + static const char* ErrorMsg(int message_code) + { + static const char* error_msg[] = + { + "No errors", "Can't open file", "Invalid file", + "Invalid file: OFF file should have in the first line the OFF keyword as a first token", + "Unsupported format", "Face with more than 3 vertices","File with high dimensional vertexes are not supported", "Error Degenerate Face with less than 3 vertices" }; - if(message_code>6 || message_code<0) - return "Unknown error"; - else - return error_msg[message_code]; - }; + if(message_code>6 || message_code<0) + return "Unknown error"; + else + return error_msg[message_code]; + }; - /** - * Load only the properties of the 3D objects. - * - * \param filename the name of the file to read from - * \param loadmask the mask which encodes the properties - * \return the operation result - */ - static bool LoadMask(const char *filename, int &loadmask) - { - // To obtain the loading mask all the file must be parsed - // to distinguish between per-vertex and per-face color attribute. - loadmask=0; - MESH_TYPE dummyMesh; - return (Open(dummyMesh, filename, loadmask)==NoError); - } + /** + * Load only the properties of the 3D objects. + * + * \param filename the name of the file to read from + * \param loadmask the mask which encodes the properties + * \return the operation result + */ + static bool LoadMask(const char *filename, int &loadmask) + { + // To obtain the loading mask all the file must be parsed + // to distinguish between per-vertex and per-face color attribute. + loadmask=0; + MESH_TYPE dummyMesh; + return (Open(dummyMesh, filename, loadmask)==NoError); + } - static int Open(MESH_TYPE &mesh, const char *filename,CallBackPos *cb=0) - { - int loadmask; - return Open(mesh,filename,loadmask,cb); - } + static int Open(MESH_TYPE &mesh, const char *filename,CallBackPos *cb=0) + { + int loadmask; + return Open(mesh,filename,loadmask,cb); + } - /*! - * Standard call for reading a mesh. - * - * \param mesh the destination mesh - * \param filename the name of the file to read from - * \return the operation result - */ - static int Open(MESH_TYPE &mesh, const char *filename, int &loadmask, - CallBackPos *cb=0) - { - std::ifstream stream(filename); - if (stream.fail()) - return CantOpen; + /*! + * Standard call for reading a mesh. + * + * \param mesh the destination mesh + * \param filename the name of the file to read from + * \return the operation result + */ + static int Open(MESH_TYPE &mesh, const char *filename, int &loadmask, + CallBackPos *cb=0) + { + std::ifstream stream(filename); + if (stream.fail()) + return CantOpen; - std::vector< std::string > tokens; - TokenizeNextLine(stream, tokens); + std::vector< std::string > tokens; + TokenizeNextLine(stream, tokens); - bool isNormalDefined = false; - bool isColorDefined = false; - bool isTexCoordDefined = false; - int dimension = 3; - bool homogeneousComponents = false; + bool isNormalDefined = false; + bool isColorDefined = false; + bool isTexCoordDefined = false; + int dimension = 3; + bool homogeneousComponents = false; - /* - [ST][C][N][4][n]OFF # Header keyword - [Ndim] # Space dimension of vertices, present only if nOFF - NVertices NFaces NEdges # NEdges not used or checked + /* + [ST][C][N][4][n]OFF # Header keyword + [Ndim] # Space dimension of vertices, present only if nOFF + NVertices NFaces NEdges # NEdges not used or checked - x[0] y[0] z[0] # Vertices, possibly with normals, colors, and/or texture coordinates, in that order, if the prefixes N, C, ST are present. - # If 4OFF, each vertex has 4 components including a final homogeneous component. - # If nOFF, each vertex has Ndim components. - # If 4nOFF, each vertex has Ndim+1 components. - ... - x[NVertices-1] y[NVertices-1] z[NVertices-1] + x[0] y[0] z[0] # Vertices, possibly with normals, colors, and/or texture coordinates, in that order, if the prefixes N, C, ST are present. + # If 4OFF, each vertex has 4 components including a final homogeneous component. + # If nOFF, each vertex has Ndim components. + # If 4nOFF, each vertex has Ndim+1 components. + ... + x[NVertices-1] y[NVertices-1] z[NVertices-1] - # Faces - # Nv = # vertices on this face - # v[0] ... v[Nv-1]: vertex indices - # in range 0..NVertices-1 - Nv v[0] v[1] ... v[Nv-1] colorspec - ... - # colorspec continues past v[Nv-1] to end-of-line; may be 0 to 4 numbers - # nothing: default - # integer: colormap index - # 3 or 4 integers: RGB[A] values 0..255 - # 3 or 4 floats: RGB[A] values 0..1 - */ - std::string header = tokens[0]; - if (header.rfind("OFF") != std::basic_string::npos) - { // the OFF string is in the header go on parsing it. - for (int u = static_cast(header.rfind("OFF")-1); u>=0; u--) - { - if (header[u] == 'C') isColorDefined = true; - else if (header[u] == 'N') isNormalDefined = true; - else if (u>0 && header[u-1] == 'S' && header[u] == 'T') isTexCoordDefined = true; - else if (header[u] == '4') homogeneousComponents = true; - else if (header[u] == 'n') return ErrorHighDimension; - } - } - else return InvalidFile_MissingOFF; + # Faces + # Nv = # vertices on this face + # v[0] ... v[Nv-1]: vertex indices + # in range 0..NVertices-1 + Nv v[0] v[1] ... v[Nv-1] colorspec + ... + # colorspec continues past v[Nv-1] to end-of-line; may be 0 to 4 numbers + # nothing: default + # integer: colormap index + # 3 or 4 integers: RGB[A] values 0..255 + # 3 or 4 floats: RGB[A] values 0..1 + */ + std::string header = tokens[0]; + if (header.rfind("OFF") != std::basic_string::npos) + { // the OFF string is in the header go on parsing it. + for (int u = static_cast(header.rfind("OFF")-1); u>=0; u--) + { + if (header[u] == 'C') isColorDefined = true; + else if (header[u] == 'N') isNormalDefined = true; + else if (u>0 && header[u-1] == 'S' && header[u] == 'T') isTexCoordDefined = true; + else if (header[u] == '4') homogeneousComponents = true; + else if (header[u] == 'n') return ErrorHighDimension; + } + } + else return InvalidFile_MissingOFF; - // If the file is slightly malformed and it has nvert and nface AFTER the OFF string instead of in the next line - // we manage it here... - if(tokens.size()==1) TokenizeNextLine(stream, tokens); - else tokens.erase(tokens.begin(),tokens.begin()+1); + // If the file is slightly malformed and it has nvert and nface AFTER the OFF string instead of in the next line + // we manage it here... + if(tokens.size()==1) TokenizeNextLine(stream, tokens); + else tokens.erase(tokens.begin(),tokens.begin()+1); - // Update loading mask - /////////////////////////////////////// + // Update loading mask + /////////////////////////////////////// - loadmask = Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX; + loadmask = Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX; - if (isNormalDefined) loadmask |= Mask::IOM_VERTNORMAL; - if (isTexCoordDefined) loadmask |= Mask::IOM_VERTTEXCOORD; - if (isColorDefined) { loadmask |= Mask::IOM_VERTCOLOR;loadmask |= Mask::IOM_FACECOLOR;} + if (isNormalDefined) loadmask |= Mask::IOM_VERTNORMAL; + if (isTexCoordDefined) loadmask |= Mask::IOM_VERTTEXCOORD; + if (isColorDefined) { loadmask |= Mask::IOM_VERTCOLOR;loadmask |= Mask::IOM_FACECOLOR;} - //if(onlyMaskFlag) return NoError; + //if(onlyMaskFlag) return NoError; - mesh.Clear(); + mesh.Clear(); - // check on next 2 lines to detect corrupted files - if(tokens.size() < 3) - return InvalidFile; + // check on next 2 lines to detect corrupted files + if(tokens.size() < 3) + return InvalidFile; - unsigned int nVertices, nFaces, nEdges; - nVertices = atoi(tokens[0].c_str()); - nFaces = atoi(tokens[1].c_str()); - nEdges = atoi(tokens[2].c_str()); + unsigned int nVertices, nFaces, nEdges; + nVertices = atoi(tokens[0].c_str()); + nFaces = atoi(tokens[1].c_str()); + nEdges = atoi(tokens[2].c_str()); - // dimension is the space dimension of vertices => it must be three(!) - if (dimension != 3) - return UnsupportedFormat; + // dimension is the space dimension of vertices => it must be three(!) + if (dimension != 3) + return UnsupportedFormat; - if (homogeneousComponents) - return UnsupportedFormat; + if (homogeneousComponents) + return UnsupportedFormat; - // READ VERTICES - ////////////////////////////////////////////////////// + // READ VERTICES + ////////////////////////////////////////////////////// - VertexIterator v_iter = Allocator::AddVertices(mesh, nVertices); - TokenizeNextLine(stream, tokens); - size_t k = 0; // next token to read + VertexIterator v_iter = Allocator::AddVertices(mesh, nVertices); + TokenizeNextLine(stream, tokens); + size_t k = 0; // next token to read - for (unsigned int i=0; i(tokens.size()) - - static_cast(k) /* tokens already parsed */ - - 2 * (isTexCoordDefined ? 1 : 0); + // NOTE: It is assumed that colored vertex takes exactly one text line + // (otherwise it is impossible to parse color information since + // color components can vary) + if (isColorDefined) + { + // The number of color components varies from 0 to 4. + // The OFF format guaranties that there is 1 vertex per line. + int nb_color_components = static_cast(tokens.size()) + - static_cast(k) /* tokens already parsed */ + - 2 * (isTexCoordDefined ? 1 : 0); - if (nb_color_components < 0 || nb_color_components > 4) - return InvalidFile; + if (nb_color_components < 0 || nb_color_components > 4) + return InvalidFile; - // set per-vertex color attribute - if (nb_color_components > 0) - loadmask |= Mask::IOM_VERTCOLOR; + // set per-vertex color attribute + if (nb_color_components > 0) + loadmask |= Mask::IOM_VERTCOLOR; - // Store color components - if (tri::HasPerVertexColor(mesh)) - { - // Read color components + // Store color components + if (tri::HasPerVertexColor(mesh)) + { + // Read color components - if (nb_color_components == 1) - { - // read color index - (*v_iter).C().Import(ColorMap(atoi(tokens[k].c_str()))); - } - else if (nb_color_components == 3) - { - // read RGB color - if (tokens[k].find(".") == size_t(-1))// if it is a float there is a dot - { - // integers - unsigned char r = - static_cast(atoi(tokens[k].c_str())); - unsigned char g = - static_cast(atoi(tokens[k+1].c_str())); - unsigned char b = - static_cast(atoi(tokens[k+2].c_str())); + if (nb_color_components == 1) + { + // read color index + (*v_iter).C().Import(ColorMap(atoi(tokens[k].c_str()))); + } + else if (nb_color_components == 3) + { + // read RGB color + if (tokens[k].find(".") == size_t(-1))// if it is a float there is a dot + { + // integers + unsigned char r = + static_cast(atoi(tokens[k].c_str())); + unsigned char g = + static_cast(atoi(tokens[k+1].c_str())); + unsigned char b = + static_cast(atoi(tokens[k+2].c_str())); - vcg::Color4b color(r, g, b, 255); - (*v_iter).C().Import(color); - } - else - { - // floats - float r = static_cast(atof(tokens[k].c_str())); - float g = static_cast(atof(tokens[k+1].c_str())); - float b = static_cast(atof(tokens[k+2].c_str())); + vcg::Color4b color(r, g, b, 255); + (*v_iter).C().Import(color); + } + else + { + // floats + float r = static_cast(atof(tokens[k].c_str())); + float g = static_cast(atof(tokens[k+1].c_str())); + float b = static_cast(atof(tokens[k+2].c_str())); - vcg::Color4f color(r, g, b, 1.0); - (*v_iter).C().Import(color); - } - } - else if (nb_color_components == 4) - { - // read RGBA color - if (tokens[k].find(".") == size_t(-1)) - { - // integers - unsigned char r = - static_cast(atoi(tokens[k].c_str())); - unsigned char g = - static_cast(atoi(tokens[k+1].c_str())); - unsigned char b = - static_cast(atoi(tokens[k+2].c_str())); - unsigned char a = - static_cast(atoi(tokens[k+3].c_str())); + vcg::Color4f color(r, g, b, 1.0); + (*v_iter).C().Import(color); + } + } + else if (nb_color_components == 4) + { + // read RGBA color + if (tokens[k].find(".") == size_t(-1)) + { + // integers + unsigned char r = + static_cast(atoi(tokens[k].c_str())); + unsigned char g = + static_cast(atoi(tokens[k+1].c_str())); + unsigned char b = + static_cast(atoi(tokens[k+2].c_str())); + unsigned char a = + static_cast(atoi(tokens[k+3].c_str())); - Color4b color(r, g, b, a); - (*v_iter).C().Import(color); - } - else - { - // floats - float r = static_cast(atof(tokens[k].c_str())); - float g = static_cast(atof(tokens[k+1].c_str())); - float b = static_cast(atof(tokens[k+2].c_str())); - float a = static_cast(atof(tokens[k+3].c_str())); + Color4b color(r, g, b, a); + (*v_iter).C().Import(color); + } + else + { + // floats + float r = static_cast(atof(tokens[k].c_str())); + float g = static_cast(atof(tokens[k+1].c_str())); + float b = static_cast(atof(tokens[k+2].c_str())); + float a = static_cast(atof(tokens[k+3].c_str())); - vcg::Color4f color(r, g, b, a); - (*v_iter).C().Import(color); - } - } - } + vcg::Color4f color(r, g, b, a); + (*v_iter).C().Import(color); + } + } + } - k += nb_color_components; - } + k += nb_color_components; + } - if (isTexCoordDefined) - { - for (unsigned int j=0; j<2; j++) - { - // Go to next line when needed - if (k == tokens.size()) // if EOL - { - TokenizeNextLine(stream, tokens); - if (tokens.size() == 0) // if EOF - return InvalidFile; - k = 0; - } + if (isTexCoordDefined) + { + for (unsigned int j=0; j<2; j++) + { + // Go to next line when needed + if (k == tokens.size()) // if EOL + { + TokenizeNextLine(stream, tokens); + if (tokens.size() == 0) // if EOF + return InvalidFile; + k = 0; + } - std::string str = tokens[k]; - k++; + std::string str = tokens[k]; + k++; - // Store texture coordinates - if (tri::HasPerWedgeTexCoord(mesh)) - { - //...TODO... - } - } - } - } // for i=... + // Store texture coordinates + if (tri::HasPerWedgeTexCoord(mesh)) + { + //...TODO... + } + } + } + } // for i=... - // READ FACES - ////////////////////////////////////////////////////// + // READ FACES + ////////////////////////////////////////////////////// - Allocator::AddFaces(mesh, nFaces); - unsigned int f0=0; + Allocator::AddFaces(mesh, nFaces); + unsigned int f0=0; - // Initial call to the QuadTriangulate with an empty vector to just reset the static set of existing diagonals - std::vector qtmp; - BitQuad::QuadTriangulate(qtmp); + // Initial call to the QuadTriangulate with an empty vector to just reset the static set of existing diagonals + std::vector qtmp; + BitQuad::QuadTriangulate(qtmp); - for (unsigned int f=0; f < nFaces; f++) - { - f0 = f; - if (stream.fail()) - return InvalidFile; + for (unsigned int f=0; f < nFaces; f++) + { + f0 = f; + if (stream.fail()) + return InvalidFile; - if(cb && (f%1000)==0) - cb(50+f*50/nFaces,"Face Loading"); + if(cb && (f%1000)==0) + cb(50+f*50/nFaces,"Face Loading"); - TokenizeNextLine(stream, tokens); - int vert_per_face = atoi(tokens[0].c_str()); - if(vert_per_face < 3) - return ErrorDegenerateFace; - k = 1; - if (vert_per_face == 3) - { - for (int j = 0; j < 3; j++) - { - if (k == tokens.size()) // if EOL // Go to next line when needed - { - TokenizeNextLine(stream, tokens); - if (tokens.size() == 0) return InvalidFile; // if EOF - k = 0; - } + TokenizeNextLine(stream, tokens); + int vert_per_face = atoi(tokens[0].c_str()); + if(vert_per_face < 3) + return ErrorDegenerateFace; + k = 1; + if (vert_per_face == 3) + { + for (int j = 0; j < 3; j++) + { + if (k == tokens.size()) // if EOL // Go to next line when needed + { + TokenizeNextLine(stream, tokens); + if (tokens.size() == 0) return InvalidFile; // if EOF + k = 0; + } - mesh.face[f].V(j) = &(mesh.vert[ atoi(tokens[k].c_str()) ]); - k++; - } - } - else - { - // The face must be triangulated - unsigned int trigs = vert_per_face-3; // number of extra faces to add - nFaces += trigs; - Allocator::AddFaces(mesh, trigs); - std::vector vertIndices(vert_per_face); - std::vector polygonVect(vert_per_face); // vec of polygon loops used for the triangulation of polygonal face - for (int j=0; j < vert_per_face; j++) - { - if (k == tokens.size()) // if EOL // Go to next line when needed - { - TokenizeNextLine(stream, tokens); - if (tokens.size() == 0) return InvalidFile; // if EOF - k = 0; - } - vertIndices[j] = atoi(tokens[k].c_str()); - polygonVect[j].Import (mesh.vert[ vertIndices[j] ].P()); - k++; - } - if(vert_per_face==4) - { // To well triangulate use the bitquad support function that reorders vertex for a simple fan - std::vector q(4); - for(int qqi=0;qqi<4;++qqi) - q[qqi]=& mesh.vert[vertIndices[qqi]]; - BitQuad::QuadTriangulate(q); - for(int qqi=0;qqi<4;++qqi) - vertIndices[qqi] = q[qqi]- & mesh.vert[0]; - // build a two face fan - for (int j=0; j<2; j++) - { - mesh.face[f+j].V(0) = &(mesh.vert[ vertIndices[0 ] ]); - mesh.face[f+j].V(1) = &(mesh.vert[ vertIndices[1+j] ]); - mesh.face[f+j].V(2) = &(mesh.vert[ vertIndices[2+j] ]); - if (tri::HasPerFaceFlags(mesh)) { - // tag internal polygonal edges as "faux" - if (j>0) mesh.face[f+j].SetF(0); - if (j indexTriangulatedVect; - // TessellatePlanarPolygon3(polygonVect,indexTriangulatedVect); - std::vector< std::vector > loopVect; - loopVect.push_back(polygonVect); + mesh.face[f].V(j) = &(mesh.vert[ atoi(tokens[k].c_str()) ]); + k++; + } + } + else + { + // The face must be triangulated + unsigned int trigs = vert_per_face-3; // number of extra faces to add + nFaces += trigs; + Allocator::AddFaces(mesh, trigs); + std::vector vertIndices(vert_per_face); + std::vector polygonVect(vert_per_face); // vec of polygon loops used for the triangulation of polygonal face + for (int j=0; j < vert_per_face; j++) + { + if (k == tokens.size()) // if EOL // Go to next line when needed + { + TokenizeNextLine(stream, tokens); + if (tokens.size() == 0) return InvalidFile; // if EOF + k = 0; + } + vertIndices[j] = atoi(tokens[k].c_str()); + polygonVect[j].Import (mesh.vert[ vertIndices[j] ].P()); + k++; + } + if(vert_per_face==4) + { // To well triangulate use the bitquad support function that reorders vertex for a simple fan + std::vector q(4); + for(int qqi=0;qqi<4;++qqi) + q[qqi]=& mesh.vert[vertIndices[qqi]]; + BitQuad::QuadTriangulate(q); + for(int qqi=0;qqi<4;++qqi) + vertIndices[qqi] = q[qqi]- & mesh.vert[0]; + // build a two face fan + for (int j=0; j<2; j++) + { + mesh.face[f+j].V(0) = &(mesh.vert[ vertIndices[0 ] ]); + mesh.face[f+j].V(1) = &(mesh.vert[ vertIndices[1+j] ]); + mesh.face[f+j].V(2) = &(mesh.vert[ vertIndices[2+j] ]); + if (tri::HasPerFaceFlags(mesh)) { + // tag internal polygonal edges as "faux" + if (j>0) mesh.face[f+j].SetF(0); + if (j indexTriangulatedVect; + // TessellatePlanarPolygon3(polygonVect,indexTriangulatedVect); + std::vector< std::vector > loopVect; + loopVect.push_back(polygonVect); #ifdef __gl_h_ //qDebug("OK: using opengl tessellation for a polygon of %i vertices",vertexesPerFace); vcg::glu_tesselator::tesselate(loopVect, indexTriangulatedVect); #else //qDebug("Warning: using fan tessellation for a polygon of %i vertices",vertexesPerFace); - ImporterOBJ::InternalFanTessellator(loopVect, indexTriangulatedVect); + tri::io::FanTessellator(loopVect, indexTriangulatedVect); #endif for (size_t j=0; j0); - if(isColorDefined) loadmask |= Mask::IOM_FACECOLOR; + // NOTE: It is assumed that colored face takes exactly one text line + // (otherwise it is impossible to parse color information since + // color components can vary) + size_t color_elements = tokens.size() - vert_per_face-1; + isColorDefined |= (color_elements>0); + if(isColorDefined) loadmask |= Mask::IOM_FACECOLOR; - if( (color_elements>0) && tri::HasPerFaceColor(mesh) ) - { + if( (color_elements>0) && tri::HasPerFaceColor(mesh) ) + { - // set per-face color attribute - if (color_elements > 0) - loadmask |= Mask::IOM_FACECOLOR; + // set per-face color attribute + if (color_elements > 0) + loadmask |= Mask::IOM_FACECOLOR; - switch (color_elements) - { - case 0: - { - for ( ; f0<=f; f0++) - mesh.face[f0].C().Import(vcg::Color4f(.666f, .666f, .666f, .666f)); - break; - } - case 1: - { - for ( ; f0<=f; f0++) - mesh.face[f0].C().Import( ColorMap( atoi(tokens[vert_per_face+1].c_str()) ) ); - break; - } - case 3: - { - if (tokens[vert_per_face+1].find('.')==std::string::npos) // if there is a float there is a dot - { - Color4b cc(Color4b::White); - cc[0] = (unsigned char)atoi( tokens[vert_per_face+1].c_str() ); - cc[1] = (unsigned char)atoi( tokens[vert_per_face+2].c_str() ); - cc[2] = (unsigned char)atoi( tokens[vert_per_face+3].c_str() ); - for ( ; f0<=f; f0++) - mesh.face[f0].C()=cc; - } - else - { - float color[3]; - color[0] = (float) atof( tokens[vert_per_face+1].c_str() ); - color[1] = (float) atof( tokens[vert_per_face+2].c_str() ); - color[2] = (float) atof( tokens[vert_per_face+3].c_str() ); - for ( ; f0<=f; f0++) - mesh.face[f0].C().Import(vcg::Color4f(color[0], color[1], color[2], 1.0f)); - } - break; - } - case 4: - { - if (tokens[vert_per_face+1].find('.')==std::string::npos) // if it is a float there is a dot - { - Color4b cc; - cc[0] = (unsigned char) atoi(tokens[vert_per_face+1].c_str()); - cc[1] = (unsigned char) atoi(tokens[vert_per_face+2].c_str()); - cc[2] = (unsigned char) atoi(tokens[vert_per_face+3].c_str()); - cc[3] = (unsigned char) atoi(tokens[vert_per_face+4].c_str()); - for ( ; f0<=f; f0++) - mesh.face[f0].C()=cc; - } - else - { - float color[4]; - color[0] = float( atof(tokens[vert_per_face+1].c_str()) ); - color[1] = float( atof(tokens[vert_per_face+2].c_str()) ); - color[2] = float( atof(tokens[vert_per_face+3].c_str()) ); - color[3] = float( atof(tokens[vert_per_face+4].c_str()) ); - for ( ; f0<=f; f0++) - mesh.face[f0].C().Import(vcg::Color4f(color[0], color[1], color[2], color[3])); - } - break; - } - } //end switch - } // end if (isColorDefined) - } // end of for f=... + switch (color_elements) + { + case 0: + { + for ( ; f0<=f; f0++) + mesh.face[f0].C().Import(vcg::Color4f(.666f, .666f, .666f, .666f)); + break; + } + case 1: + { + for ( ; f0<=f; f0++) + mesh.face[f0].C().Import( ColorMap( atoi(tokens[vert_per_face+1].c_str()) ) ); + break; + } + case 3: + { + if (tokens[vert_per_face+1].find('.')==std::string::npos) // if there is a float there is a dot + { + Color4b cc(Color4b::White); + cc[0] = (unsigned char)atoi( tokens[vert_per_face+1].c_str() ); + cc[1] = (unsigned char)atoi( tokens[vert_per_face+2].c_str() ); + cc[2] = (unsigned char)atoi( tokens[vert_per_face+3].c_str() ); + for ( ; f0<=f; f0++) + mesh.face[f0].C()=cc; + } + else + { + float color[3]; + color[0] = (float) atof( tokens[vert_per_face+1].c_str() ); + color[1] = (float) atof( tokens[vert_per_face+2].c_str() ); + color[2] = (float) atof( tokens[vert_per_face+3].c_str() ); + for ( ; f0<=f; f0++) + mesh.face[f0].C().Import(vcg::Color4f(color[0], color[1], color[2], 1.0f)); + } + break; + } + case 4: + { + if (tokens[vert_per_face+1].find('.')==std::string::npos) // if it is a float there is a dot + { + Color4b cc; + cc[0] = (unsigned char) atoi(tokens[vert_per_face+1].c_str()); + cc[1] = (unsigned char) atoi(tokens[vert_per_face+2].c_str()); + cc[2] = (unsigned char) atoi(tokens[vert_per_face+3].c_str()); + cc[3] = (unsigned char) atoi(tokens[vert_per_face+4].c_str()); + for ( ; f0<=f; f0++) + mesh.face[f0].C()=cc; + } + else + { + float color[4]; + color[0] = float( atof(tokens[vert_per_face+1].c_str()) ); + color[1] = float( atof(tokens[vert_per_face+2].c_str()) ); + color[2] = float( atof(tokens[vert_per_face+3].c_str()) ); + color[3] = float( atof(tokens[vert_per_face+4].c_str()) ); + for ( ; f0<=f; f0++) + mesh.face[f0].C().Import(vcg::Color4f(color[0], color[1], color[2], color[3])); + } + break; + } + } //end switch + } // end if (isColorDefined) + } // end of for f=... - return NoError; + return NoError; - } // end Open + } // end Open - protected: + protected: - /*! - * Read the next valid line and parses it into "tokens", allowing the tokens to be read one at a time. - * \param stream The object providing the input stream - * \param tokens The "tokens" in the next line - */ - inline static void TokenizeNextLine(std::ifstream &stream, std::vector< std::string > &tokens) - { - std::string line; - do - std::getline(stream, line, '\n'); - while (line[0] == '#' || line.length()==0 || line[0]=='\r'); + /*! + * Read the next valid line and parses it into "tokens", allowing the tokens to be read one at a time. + * \param stream The object providing the input stream + * \param tokens The "tokens" in the next line + */ + inline static void TokenizeNextLine(std::ifstream &stream, std::vector< std::string > &tokens) + { + std::string line; + do + std::getline(stream, line, '\n'); + while (line[0] == '#' || line.length()==0 || line[0]=='\r'); - 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 (fromcolor mapping, according to the Geomview's `cmap.fmap' file. - * \param i the color index - * \return the corresponding vcg::Color4f color - */ - static const vcg::Color4f ColorMap(int i) - { - static const float colorMap[148][4] = - { - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.2f, 0.2f, 0.2f, 0.2f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.1f, 0.1f, 0.1f, 0.1f }, - { 0.1f, 0.1f, 0.1f, 0.1f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.2f, 0.2f, 0.2f, 0.2f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.75f, 0.75f, 0.75f, 0.75f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.75f, 0.75f, 0.75f, 0.75f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.75f, 0.75f, 0.75f, 0.75f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.75f, 0.75f, 0.75f, 0.75f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f, 1.0f }, - { 0.05f, 0.05f, 0.05f, 0.05f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.2f, 0.2f, 0.2f, 0.2f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.1f, 0.1f, 0.1f, 0.1f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.75f, 0.75f, 0.75f, 0.75f }, - { 0.75f, 0.75f, 0.75f, 0.75f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.75f, 0.75f, 0.75f, 0.75f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.75f, 0.75f, 0.75f, 0.75f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.7f, 0.7f, 0.7f, 0.7f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.9f, 0.9f, 0.9f, 0.9f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.75f, 0.75f, 0.75f, 0.75f }, - { 0.8f, 0.8f, 0.8f, 0.8f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.4f, 0.4f, 0.4f, 0.4f }, - { 0.8f, 0.8f, 0.8f, 0.8f } - }; - return Color4f(colorMap[i][0], colorMap[i][1], colorMap[i][2], colorMap[i][3]); - } - }; - // /*! @} */ - } //namespace io - }//namespace tri + /*! + * Provide the int->color mapping, according to the Geomview's `cmap.fmap' file. + * \param i the color index + * \return the corresponding vcg::Color4f color + */ + static const vcg::Color4f ColorMap(int i) + { + static const float colorMap[148][4] = + { + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.2f, 0.2f, 0.2f, 0.2f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.1f, 0.1f, 0.1f, 0.1f }, + { 0.1f, 0.1f, 0.1f, 0.1f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.2f, 0.2f, 0.2f, 0.2f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.75f, 0.75f, 0.75f, 0.75f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.75f, 0.75f, 0.75f, 0.75f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.75f, 0.75f, 0.75f, 0.75f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.75f, 0.75f, 0.75f, 0.75f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { 0.05f, 0.05f, 0.05f, 0.05f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.2f, 0.2f, 0.2f, 0.2f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.1f, 0.1f, 0.1f, 0.1f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.75f, 0.75f, 0.75f, 0.75f }, + { 0.75f, 0.75f, 0.75f, 0.75f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.75f, 0.75f, 0.75f, 0.75f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.75f, 0.75f, 0.75f, 0.75f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.7f, 0.7f, 0.7f, 0.7f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.9f, 0.9f, 0.9f, 0.9f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.75f, 0.75f, 0.75f, 0.75f }, + { 0.8f, 0.8f, 0.8f, 0.8f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.4f, 0.4f, 0.4f, 0.4f }, + { 0.8f, 0.8f, 0.8f, 0.8f } + }; + return Color4f(colorMap[i][0], colorMap[i][1], colorMap[i][2], colorMap[i][3]); + } + }; + // /*! @} */ + } //namespace io + }//namespace tri } // namespace vcg #endif //__VCGLIB_IMPORT_OFF diff --git a/wrap/io_trimesh/io_fan_tessellator.h b/wrap/io_trimesh/io_fan_tessellator.h new file mode 100644 index 00000000..954b5a98 --- /dev/null +++ b/wrap/io_trimesh/io_fan_tessellator.h @@ -0,0 +1,71 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ +#ifndef IO_FAN_TESSELLATOR_H +#define IO_FAN_TESSELLATOR_H + +namespace vcg { +namespace tri { +namespace io { + +/* +* 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 +*/ +template < class PointType> +void FanTessellator(const std::vector< std::vector > & outlines, std::vector & indices) +{ + indices.clear(); + if(outlines.empty()) return; + const std::vector &points=outlines[0]; + + for(size_t i=0;i