// swaps two index entries
static void Swap(IndexVec& v, IndexVec& n, IndexVec& t, IndexVec& c,
                 size_t sI, size_t tI) {
    std::swap(v[sI],v[tI]);
    if (v.size() == n.size()) std::swap(n[sI],n[tI]);
    if (v.size() == t.size()) std::swap(t[sI],t[tI]);
    if (v.size() == c.size()) std::swap(c[sI],c[tI]);
}
void AbstrGeoConverter::SortByGradient(const VertVec& vertices,
                                       IndexVec& v, IndexVec& n,
                                       IndexVec& t, IndexVec& c)
{
    if(v.size() < 2) return;

    // find AA projection direction that is not coplanar to the polygon
    size_t iPlaneX = 2;
    size_t iPlaneY = 1;

    FLOATVECTOR3 tan = (vertices[v[0]]-vertices[v[1]]).normalized();
    FLOATVECTOR3 bin = (vertices[v[0]]-vertices[v[2]]).normalized();
    FLOATVECTOR3 norm = tan%bin;

    if (norm.y != 0) {
        iPlaneX = 0;
        iPlaneY = 2;
    } else if (norm.z != 0) {
        iPlaneX = 0;
        iPlaneY = 1;
    } // else use default which is the x-plane

    // move bottom element to front of array
    for (size_t i = 1; i<v.size(); i++) {
        if (vertices[v[0]][iPlaneY] > vertices[v[i]][iPlaneY]) {
            Swap(v,n,t,c,0,i);
        }
    }

    // *** sort points according to gradient

    SortPoints(vertices,v,n,t,c,iPlaneX,iPlaneY);
}
static void SortPoints(const VertVec& vertices,
                       IndexVec& v, IndexVec& n,
                       IndexVec& t, IndexVec& c,
                       size_t iPlaneX, size_t iPlaneY) {
    // for small arrays, this bubble sort actually beats qsort.
    for (size_t i= 1; i<v.size(); ++i) {
        bool bDidSwap = false;
        for (size_t j = 1; j<v.size()-i; ++j)
            if (!CheckOrdering(vertices[v[j]],vertices[v[j+1]],vertices[v[0]],iPlaneX,iPlaneY)) {
                Swap(v,n,t,c,j,j+1);
                bDidSwap = true;
            }
        if (!bDidSwap) return;
    }

}
Exemple #4
0
//-*****************************************************************************
void AbcReader::f( const IndexVec &vIndices,
                   const IndexVec &vtIndices,
                   const IndexVec &vnIndices )
{
    int count = vIndices.size();
    if ( count > 2 )
    {
        m_counts.push_back( count );
        for ( int i = 0; i < count; ++i )
        {
            m_indices.push_back( ( int )( vIndices[i]-1 ) );
        }
    }
}
Exemple #5
0
void RenderMeshGL::PrepareTransBuffers(GLuint IndexVBO, const SortIndexPVec& list) {
  if (list.empty()) return;

  IndexVec VertIndices;
  VertIndices.reserve(list.size());
  for(SortIndexPVec::const_iterator index = list.begin(); index != list.end();
      ++index) {
    size_t iIndex = (*index)->m_index;
    for(size_t i = 0;i<m_VerticesPerPoly;i++) {
      VertIndices.push_back(m_Data.m_VertIndices[iIndex+i]);
    }
  }

  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBO);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, VertIndices.size()*sizeof(uint32_t),
               &VertIndices[0], GL_STREAM_DRAW);
}
std::shared_ptr<Mesh>
OBJGeoConverter::ConvertToMesh(const std::string& strFilename) {
  bool bFlipVertices = false;

  VertVec       vertices;
  NormVec       normals;
  TexCoordVec   texcoords;
  ColorVec      colors;

  IndexVec      VertIndices;
  IndexVec      NormalIndices;
  IndexVec      TCIndices;
  IndexVec      COLIndices;

	std::ifstream fs;
	std::string line;

	fs.open(strFilename.c_str());
  if (fs.fail()) {
    // hack, we really want some kind of 'file not found' exception.
    throw tuvok::io::DSOpenFailed(strFilename.c_str(), __FILE__, __LINE__);
  }

  float x,y,z,w;
  size_t iVerticesPerPoly = 0;

  fs.seekg(0,std::ios::end);
  std::streamoff iFileLength = fs.tellg();
  fs.seekg(0,std::ios::beg);
  size_t iBytesRead = 0;
  size_t iLine = 0;

  while (!fs.fail()) {
		getline(fs, line);

    iBytesRead += line.size() + 1;
    iLine++;

		if (fs.fail()) break; // no more lines to read
    line = SysTools::ToLowerCase(SysTools::TrimStr(line));

    // remove comments
    size_t cPos = line.find_first_of('#');
    if (cPos != std::string::npos) line = line.substr(0,cPos);
    line = SysTools::TrimStr(line);
    if (line.length() == 0) continue; // skips empty and comment lines

    // find the linetype
    size_t off = line.find_first_of(" \r\n\t");
    if (off == std::string::npos) continue;
    std::string linetype = SysTools::TrimStrRight(line.substr(0,off));

    line = SysTools::TrimStr(line.substr(linetype.length()));

    if (linetype == "o") { 
      WARNING("Skipping Object Tag in OBJ file");
    } else
    if (linetype == "mtllib") { 
      WARNING("Skipping Material Library Tag in OBJ file");
    } else
		if (linetype == "v") { // vertex attrib found
      std::vector< std::string > pos = SysTools::Tokenize(line, SysTools::PM_NONE);

      if (pos.size() < 3) {
        WARNING("Found broken v tag (to few coordinates, "
                "filling with zeroes");
        x = (pos.size() > 0) ? SysTools::FromString<float>(pos[0]) : 0.0f;
	      y = (pos.size() > 1) ? SysTools::FromString<float>(pos[1]) : 0.0f;
	      z = 0.0f;
      } else {
        x = SysTools::FromString<float>(pos[0]);
	      y = SysTools::FromString<float>(pos[1]);
	      z = SysTools::FromString<float>(pos[2]);

        if (pos.size() >= 6) {
          // this is a "meshlab extended" obj file that includes vertex colors
	        float r = SysTools::FromString<float>(pos[3]);
	        float g = SysTools::FromString<float>(pos[4]);
	        float b = SysTools::FromString<float>(pos[5]);
          float a = (pos.size() > 6) ? SysTools::FromString<float>(pos[6]):1.0f;
          colors.push_back(FLOATVECTOR4(r,g,b,a));
        } else if (pos.size() > 3) {
          // file specifies homogeneous coordinate
	        float w = SysTools::FromString<float>(pos[3]);
          if (w != 0) {
            x /= w;
            y /= w;
            z /= w;
          }
        }
      }
      vertices.push_back(FLOATVECTOR3(x,y,(bFlipVertices) ? -z : z));

  	} else
	  if (linetype == "vt") {  // vertex texcoord found
      x = float(atof(GetToken(line).c_str()));
			y = float(atof(GetToken(line).c_str()));
			texcoords.push_back(FLOATVECTOR2(x,y));
		} else
	  if (linetype == "vc") {  // vertex color found
      x = float(atof(GetToken(line).c_str()));
			y = float(atof(GetToken(line).c_str()));
			z = float(atof(GetToken(line).c_str()));
			w = float(atof(GetToken(line).c_str()));
			colors.push_back(FLOATVECTOR4(x,y,z,w));
		} else
    if (linetype == "vn") { // vertex normal found
      x = float(atof(GetToken(line).c_str()));
			y = float(atof(GetToken(line).c_str()));
			z = float(atof(GetToken(line).c_str()));
      FLOATVECTOR3 n(x,y,z);
      n.normalize();
      normals.push_back(n);
		} else
    if (linetype == "f" || linetype == "l") { // face or line found
      size_t off = line.find_first_of(" \r\n\t");
      if (off == std::string::npos) continue;
      std::string analysis = SysTools::TrimStrRight(line.substr(0,off));
      int count = CountOccurences(analysis,"/");

      IndexVec v, n, t, c;
      
      while (line.length() > 0)  {
        switch (count) {
          case 0 : {
                int vI = atoi(GetToken(line).c_str())-1;
                v.push_back(vI);
                break;
               }
          case 1 : {
                int vI = atoi(GetToken(line,"/",true).c_str())-1;
                v.push_back(vI);
                int vT = atoi(GetToken(line).c_str())-1;
                t.push_back(vT);
                line = TrimToken(line);
                break;
               }
          case 2 : {
                int vI = atoi(GetToken(line,"/",true).c_str())-1;
                v.push_back(vI);
                if (line[0] != '/') {
                  int vT = atoi(GetToken(line,"/",true).c_str())-1;
                  t.push_back(vT);
                }else line = TrimToken(line,"/",true);
                int vN = atoi(GetToken(line).c_str())-1;
                n.push_back(vN);
                break;
               }
          case 3 : {
                int vI = atoi(GetToken(line,"/",true).c_str())-1;
                v.push_back(vI);
                if (line[0] != '/') {
                  int vT = atoi(GetToken(line,"/",true).c_str())-1;
                  t.push_back(vT);
                }else line = TrimToken(line,"/",true);
                if (line[0] != '/') {
                  int vN = atoi(GetToken(line,"/",true).c_str())-1;
                  n.push_back(vN);
                } else line = TrimToken(line,"/",true);
                int vC = atoi(GetToken(line).c_str())-1;
                c.push_back(vC);
                break;
               }
        }
        SysTools::TrimStrLeft(line);
      }

      if (v.size() == 1) {
        WARNING("Skipping points in OBJ file");
        continue;
      }

      if (iVerticesPerPoly == 0) iVerticesPerPoly = v.size();

      if (v.size() == 2) {
        if ( iVerticesPerPoly != 2 ) {
          WARNING("Skipping a line in a file that also contains polygons");
          continue;
        }
        AddToMesh(vertices,v,n,t,c,VertIndices,NormalIndices,TCIndices,COLIndices);
      } else {
        if ( iVerticesPerPoly == 2 ) {
          WARNING("Skipping polygon in file that also contains lines");
          continue;
        }
        AddToMesh(vertices,v,n,t,c,VertIndices,NormalIndices,TCIndices,COLIndices);
      }

    } else {
      WARNING("Skipping unknown tag %s in OBJ file", linetype.c_str());
    }

    if (iLine % 5000 == 0) {
      MESSAGE("Reading line %u (%u / %u kb)", unsigned(iLine),
              unsigned(iBytesRead/1024),unsigned(iFileLength/1024));
    }

  }
	fs.close();

  std::string desc = m_vConverterDesc + " data converted from " + SysTools::GetFilename(strFilename);

  // generate color indies for "meshlab extended" format
  if (COLIndices.size() == 0 && vertices.size() == colors.size()) 
    COLIndices = VertIndices;


  std::shared_ptr<Mesh> m(
    new Mesh(vertices,normals,texcoords,colors,
             VertIndices,NormalIndices,TCIndices,COLIndices,
             false, false, desc, 
             ((iVerticesPerPoly == 2) 
                ? Mesh::MT_LINES 
                : Mesh::MT_TRIANGLES))
  );
  return m;
}
void AbstrGeoConverter::AddToMesh(const VertVec& vertices,
                                  IndexVec& v, IndexVec& n,
                                  IndexVec& t, IndexVec& c,
                                  IndexVec& VertIndices, IndexVec& NormalIndices,
                                  IndexVec& TCIndices, IndexVec& COLIndices) {
    if (v.size() > 3) {
        // per OBJ definition any poly with more than 3 verices has
        // to be planar and convex, so we can safely triangulate it
        SortByGradient(vertices,v,n,t,c);

        for (size_t i = 0; i<v.size()-2; i++) {
            IndexVec mv, mn, mt, mc;
            mv.push_back(v[0]);
            mv.push_back(v[i+1]);
            mv.push_back(v[i+2]);
            if (n.size() == v.size()) {
                mn.push_back(n[i]);
                mn.push_back(n[i+1]);
                mn.push_back(n[i+2]);
            }
            if (t.size() == v.size()) {
                mt.push_back(t[i]);
                mt.push_back(t[i+1]);
                mt.push_back(t[i+2]);
            }
            if (c.size() == v.size()) {
                mc.push_back(c[i]);
                mc.push_back(c[i+1]);
                mc.push_back(c[i+2]);
            }

            AddToMesh(vertices,
                      mv,mn,mt,mc,
                      VertIndices,
                      NormalIndices,
                      TCIndices,
                      COLIndices);
        }
    } else {
        for (size_t i = 0; i<v.size(); i++) {
            VertIndices.push_back(v[i]);
            if (n.size() == v.size()) NormalIndices.push_back(n[i]);
            if (t.size() == v.size()) TCIndices.push_back(t[i]);
            if (c.size() == v.size()) COLIndices.push_back(c[i]);
        }
    }
}
std::shared_ptr<Mesh>
PLYGeoConverter::ConvertToMesh(const std::string& strFilename) {
  VertVec       vertices;
  NormVec       normals;
  TexCoordVec   texcoords;
  ColorVec      colors;

  IndexVec      VertIndices;
  IndexVec      NormalIndices;
  IndexVec      TCIndices;
  IndexVec      COLIndices;

  std::ifstream fs;
	std::string line;

	fs.open(strFilename.c_str());
  if (fs.fail()) {
    throw tuvok::io::DSOpenFailed(strFilename.c_str(), __FILE__, __LINE__);
  }

  int iFormat = FORMAT_ASCII;
  int iReaderState = SEARCHING_MAGIC;
  size_t iVertexCount=0;
  size_t iFaceCount=0;
  size_t iLineCount=0;
  bool bNormalsFound = false;
  bool bTexCoordsFound = false;
  bool bColorsFound = false;

  MESSAGE("Reading Header");

  fs.seekg(0,std::ios::end);
  streamoff iFileLength = fs.tellg();
  fs.seekg(0,std::ios::beg);
  size_t iBytesRead = 0;
  size_t iLine = 0;

	while (!fs.fail() && iReaderState < PARSING_VERTEX_DATA) {
		getline(fs, line);
		if (fs.fail()) break; // no more lines to read

    iBytesRead += line.size() + 1;
    iLine++;
    if (iLine % 5000 == 0) {
        MESSAGE("Reading Header (Line %u %u/%u kb)", unsigned(iLine),
                unsigned(iBytesRead/1024),unsigned(iFileLength/1024));
    }

    // remove comments
    line = SysTools::TrimStr(line);
    if (line.length() == 0) continue; // skip empty lines

    // find the linetype
    string linetype = GetToken(line);
    if (linetype == "comment") continue; // skip comment lines

    switch (iReaderState) {
      case SEARCHING_MAGIC : {
                           if (linetype == "ply")
                                iReaderState = PARSING_GENERAL_HEADER;
                              else 
                                continue;
                           }
                           break;
      case PARSING_FACE_HEADER : 
      case PARSING_VERTEX_HEADER :
      case PARSING_EDGE_HEADER :
      case PARSING_GENERAL_HEADER : {
                              if (linetype == "format") {
                                string format = GetToken(line);
                                if (format == "ascii")
                                  iFormat = FORMAT_ASCII;
                                else if (format == "binary_little_endian")
                                  iFormat = FORMAT_BIN_LITTLE;
                                else if (format == "binary_big_endian")
                                  iFormat = FORMAT_BIN_BIG;
                                else {
                                  stringstream s;
                                  s << "unknown format " << format.c_str();
                                  throw tuvok::io::DSParseFailed(strFilename.c_str(), s.str().c_str(),__FILE__, __LINE__);
                                }
                                string version = GetToken(line);
                                if (version != "1.0") {
                                  stringstream s;
                                  s << "unknown version " << version.c_str();
                                  throw tuvok::io::DSParseFailed(strFilename.c_str(), s.str().c_str(),__FILE__, __LINE__);
                                }
                              } else if (linetype == "element") {
                                string elemType = GetToken(line);
                                if (elemType == "vertex") {
                                  iReaderState = PARSING_VERTEX_HEADER;
                                  string strCount = GetToken(line);
                                  iVertexCount = atoi(strCount.c_str());
                                } else if (elemType == "face") {
                                  iReaderState = PARSING_FACE_HEADER;
                                  string strCount = GetToken(line);
                                  iFaceCount = atoi(strCount.c_str());
                                } else if (elemType == "edge") {
                                  iReaderState = PARSING_EDGE_HEADER;
                                  string strCount = GetToken(line);
                                  iLineCount = atoi(strCount.c_str());
                                }
                              } else if (linetype == "property") {
                                if (iReaderState == PARSING_VERTEX_HEADER){
                                  propType t = StringToType(GetToken(line));
                                  vertexProp p = StringToVProp(GetToken(line));
                                  vertexProps.push_back(make_pair(t,p));
                                } else if (iReaderState == PARSING_FACE_HEADER) {
                                  faceProp p = StringToFProp(GetToken(line));
                                  propType t1 = StringToType(GetToken(line));
                                  propType t2 = StringToType(GetToken(line));
                                  faceProps.push_back(make_tuple(t1,t2,p));
                                } else if (iReaderState == PARSING_EDGE_HEADER) {
                                  propType t = StringToType(GetToken(line));
                                  edgeProp p = StringToEProp(GetToken(line));
                                  edgeProps.push_back(make_pair(t,p));
                                } else {
                                  WARNING("property outside vertex or face data found");
                                }
                              } else if (linetype == "end_header") {
                                iReaderState = PARSING_VERTEX_DATA;
                              } 
                           }
                           break;
      default : throw tuvok::io::DSParseFailed(strFilename.c_str(), "unknown parser state header",__FILE__, __LINE__);
    }
  }

  if (iFormat != FORMAT_ASCII) {
    throw tuvok::io::DSParseFailed(strFilename.c_str(), "Binary PLY files not supported yet.",__FILE__, __LINE__);
  }

  if (iFaceCount > 0 && iLineCount > 0) {
    WARNING("found both, polygons and lines, in the file, ignoring lines");
  }

  MESSAGE("Reading Vertices");

  size_t iFacesFound = 0;
  vertices.reserve(iVertexCount);
  // parse data body of PLY file
	while (!fs.fail() && iReaderState != PARSING_DONE) {
		getline(fs, line);
		if (fs.fail()) break; // no more lines to read

    iBytesRead += line.size() + 1;
    iLine++;
    if (iLine % 5000 == 0) {
      if (PARSING_VERTEX_DATA) 
        MESSAGE("Reading Vertices (Line %u %u/%u kb)", unsigned(iLine),
                unsigned(iBytesRead/1024),unsigned(iFileLength/1024));
      else
        MESSAGE("Reading Indices (Line %u %u/%u kb)", unsigned(iLine),
                unsigned(iBytesRead/1024),unsigned(iFileLength/1024));
    }


    line = SysTools::TrimStr(line);

    if (iReaderState == PARSING_VERTEX_DATA) {
      FLOATVECTOR3 pos;
      FLOATVECTOR3 normal(0,0,0);
      FLOATVECTOR4 color(0,0,0,1);
      
      for (size_t i = 0;i<vertexProps.size();i++) {
        string strValue = GetToken(line);


        double fValue=0.0; int iValue=0;
        if (vertexProps[i].first <= PROPT_DOUBLE) {
          fValue = atof(strValue.c_str());
          iValue = int(fValue);
        } else {
          iValue = atoi(strValue.c_str());
          fValue = double(iValue);
        }

        switch (vertexProps[i].second) {
          case VPROP_X         : pos.x = float(fValue); break;
          case VPROP_Y         : pos.y = float(fValue); break;
          case VPROP_Z         : pos.z = float(fValue); break;
          case VPROP_NX        : bNormalsFound = true; normal.x = float(fValue); break;
          case VPROP_NY        : bNormalsFound = true; normal.y = float(fValue); break;
          case VPROP_NZ        : bNormalsFound = true; normal.z = float(fValue); break;
          case VPROP_RED       : bColorsFound = true; color.x = (vertexProps[i].first <= PROPT_DOUBLE) ? float(fValue) : iValue/255.0f; break;
          case VPROP_GREEN     : bColorsFound = true; color.y = (vertexProps[i].first <= PROPT_DOUBLE) ? float(fValue) : iValue/255.0f; break;
          case VPROP_BLUE      : bColorsFound = true; color.z = (vertexProps[i].first <= PROPT_DOUBLE) ? float(fValue) : iValue/255.0f; break;
          case VPROP_OPACITY   : bColorsFound = true; color.w = (vertexProps[i].first <= PROPT_DOUBLE) ? float(fValue) : iValue/255.0f; break;
          case VPROP_INTENSITY : bColorsFound = true;                                 
                                 color = (vertexProps[i].first <= PROPT_DOUBLE) ? FLOATVECTOR4(float(fValue),float(fValue),float(fValue),1.0f)
                                                                                : FLOATVECTOR4(iValue/255.0f,iValue/255.0f,iValue/255.0f,1.0f);
                                 break;
          default: break;
        }
      }

      vertices.push_back(pos);
      if (bColorsFound) colors.push_back(color);
      if (bNormalsFound) normals.push_back(normal);

      if (vertices.size() == iVertexCount) {
        iReaderState = (iFaceCount > 0) ? PARSING_FACE_DATA : PARSING_EDGE_DATA;
        MESSAGE("Reading Faces");
      }
    } else if (iReaderState == PARSING_FACE_DATA) {

      IndexVec v, n, t, c;
      for (size_t i = 0;i<faceProps.size();i++) {
        string strValue = GetToken(line);

        double fValue=0.0; int iValue=0;
        if (std::get<1>(faceProps[i]) <= PROPT_DOUBLE) {
          fValue = atof(strValue.c_str());
          iValue = static_cast<int>(fValue);
        } else {
          iValue = atoi(strValue.c_str());
          fValue = static_cast<double>(iValue);
        }

        switch (std::get<2>(faceProps[i])) {
          case FPROP_LIST : {
                              for (int j = 0;j<iValue;j++) {
                                // hack: read everything as int, regardless of the 
                                //       type stored in std::get<1>(faceProps[i])
                                strValue = GetToken(line);
                                int elem = atoi(strValue.c_str());
                                v.push_back(elem);
                                if (bNormalsFound) n.push_back(elem);
                                if (bTexCoordsFound) t.push_back(elem);
                                if (bColorsFound) c.push_back(elem);
                              }
                            }
                            break;
          default: break;
        }
      }
      AddToMesh(vertices,v,n,t,c,VertIndices,NormalIndices,TCIndices,COLIndices);

      iFacesFound++;
      if (iFacesFound == iFaceCount) iReaderState = PARSING_DONE;
    } else if (iReaderState == PARSING_EDGE_DATA) {
      FLOATVECTOR4 color(0,0,0,1);
      bool bEdgeColorsFound=false;

      for (size_t i = 0;i<edgeProps.size();i++) {
        string strValue = GetToken(line);

        double fValue=0.0; int iValue=0;
        if (edgeProps[i].first <= PROPT_DOUBLE) {
          fValue = atof(strValue.c_str());
          iValue = int(fValue);
        } else {
          iValue = atoi(strValue.c_str());
          fValue = double(iValue);
        }
        switch (edgeProps[i].second) {
          case EPROP_VERTEX1   : VertIndices.push_back(iValue); break;
          case EPROP_VERTEX2   : VertIndices.push_back(iValue); break;
          case EPROP_RED       : bEdgeColorsFound = true; color.x = (edgeProps[i].first <= PROPT_DOUBLE) ? float(fValue) : iValue/255.0f; break;
          case EPROP_GREEN     : bEdgeColorsFound = true; color.y = (edgeProps[i].first <= PROPT_DOUBLE) ? float(fValue) : iValue/255.0f; break;
          case EPROP_BLUE      : bEdgeColorsFound = true; color.z = (edgeProps[i].first <= PROPT_DOUBLE) ? float(fValue) : iValue/255.0f; break;
          case EPROP_OPACITY   : bEdgeColorsFound = true; color.w = (edgeProps[i].first <= PROPT_DOUBLE) ? float(fValue) : iValue/255.0f; break;
          case EPROP_INTENSITY : bEdgeColorsFound = true;                                 
                                 color = (edgeProps[i].first <= PROPT_DOUBLE) ? FLOATVECTOR4(float(fValue),float(fValue),float(fValue),1.0f)
                                                                              : FLOATVECTOR4(iValue/255.0f,iValue/255.0f,iValue/255.0f,1.0f);
                                 break;
          default: break;
        }
      }

      if (bEdgeColorsFound)  {
        COLIndices.push_back(uint32_t(colors.size()));
        COLIndices.push_back(uint32_t(colors.size()));
        colors.push_back(color);
      }

      if (VertIndices.size() == iLineCount*2) iReaderState = PARSING_DONE;
    } else throw tuvok::io::DSParseFailed(strFilename.c_str(), "unknown parser state data",__FILE__, __LINE__);
  }

  MESSAGE("Creating Mesh Object");

  std::string desc = m_vConverterDesc + " data converted from " + SysTools::GetFilename(strFilename);

  return std::shared_ptr<Mesh>(
    new Mesh(vertices,normals,texcoords,colors,
             VertIndices,NormalIndices,TCIndices,COLIndices,
             false,false,desc, (iFaceCount > 0) ? Mesh::MT_TRIANGLES
                                                : Mesh::MT_LINES)
  );
}