OBJReader.cc 23.3 KB
Newer Older
Jan Möbius's avatar
Jan Möbius committed
1
/* ========================================================================= *
Jan Möbius's avatar
Jan Möbius committed
2 3
 *                                                                           *
 *                               OpenMesh                                    *
Jan Möbius's avatar
Jan Möbius committed
4
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
Jan Möbius's avatar
Typo  
Jan Möbius committed
5
 *           Department of Computer Graphics and Multimedia                  *
Jan Möbius's avatar
Jan Möbius committed
6 7
 *                          All rights reserved.                             *
 *                            www.openmesh.org                               *
Jan Möbius's avatar
Jan Möbius committed
8
 *                                                                           *
9
 *---------------------------------------------------------------------------*
Jan Möbius's avatar
Jan Möbius committed
10 11
 * This file is part of OpenMesh.                                            *
 *---------------------------------------------------------------------------*
12
 *                                                                           *
Jan Möbius's avatar
Jan Möbius committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
 *                                                                           *
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
 *                                                                           *
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
 *                                                                           *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           *
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
Jan Möbius's avatar
Jan Möbius committed
39 40
 *                                                                           *
 * ========================================================================= */
41

42

Jan Möbius's avatar
Jan Möbius committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65


//== INCLUDES =================================================================


// OpenMesh
#include <OpenMesh/Core/IO/reader/OBJReader.hh>
#include <OpenMesh/Core/IO/IOManager.hh>
#include <OpenMesh/Core/Utils/vector_cast.hh>
#include <OpenMesh/Core/Utils/color_cast.hh>
// STL
#if defined(OM_CC_MIPS)
#  include <ctype.h>
/// \bug Workaround for STLPORT 4.6: isspace seems not to be in namespace std!
#elif defined(_STLPORT_VERSION) && (_STLPORT_VERSION==0x460)
#  include <cctype>
#else
using std::isspace;
#endif

#ifndef WIN32
#endif

66
#include <fstream>
67

Jan Möbius's avatar
Jan Möbius committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
//=== NAMESPACES ==============================================================


namespace OpenMesh {
namespace IO {


//=== INSTANCIATE =============================================================


_OBJReader_  __OBJReaderInstance;
_OBJReader_& OBJReader() { return __OBJReaderInstance; }


//=== IMPLEMENTATION ==========================================================

84 85 86 87 88
//-----------------------------------------------------------------------------

void trimString( std::string& _string) {
  // Trim Both leading and trailing spaces

89 90
  size_t start = _string.find_first_not_of(" \t\r\n");
  size_t end   = _string.find_last_not_of(" \t\r\n");
91 92 93 94 95 96 97

  if(( std::string::npos == start ) || ( std::string::npos == end))
    _string = "";
  else
    _string = _string.substr( start, end-start+1 );
}

98 99 100 101 102
//-----------------------------------------------------------------------------

// remove duplicated indices from one face
void remove_duplicated_vertices(BaseImporter::VHandles& _indices)
{
103 104 105 106 107
  BaseImporter::VHandles::iterator endIter = _indices.end();
  for (BaseImporter::VHandles::iterator iter = _indices.begin(); iter != endIter; ++iter)
    endIter = std::remove(iter+1, endIter, *(iter));

  _indices.erase(endIter,_indices.end());
108 109
}

110
//-----------------------------------------------------------------------------
Jan Möbius's avatar
Jan Möbius committed
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127

_OBJReader_::
_OBJReader_()
{
  IOManager().register_module(this);
}


//-----------------------------------------------------------------------------


bool
_OBJReader_::
read(const std::string& _filename, BaseImporter& _bi, Options& _opt)
{
  std::fstream in( _filename.c_str(), std::ios_base::in );

128
  if (!in.is_open() || !in.good())
Jan Möbius's avatar
Jan Möbius committed
129 130 131 132 133 134 135 136 137
  {
    omerr() << "[OBJReader] : cannot not open file "
          << _filename
          << std::endl;
    return false;
  }

  {
#if defined(WIN32)
Jan Möbius's avatar
Jan Möbius committed
138
    std::string::size_type dot_pos = _filename.find_last_of("\\/");
Jan Möbius's avatar
Jan Möbius committed
139
#else
Jan Möbius's avatar
Jan Möbius committed
140
    std::string::size_type dot_pos = _filename.rfind("/");
Jan Möbius's avatar
Jan Möbius committed
141
#endif
Jan Möbius's avatar
Jan Möbius committed
142
    path_ = (dot_pos == std::string::npos)
Jan Möbius's avatar
Jan Möbius committed
143
      ? "./"
Jan Möbius's avatar
Jan Möbius committed
144
      : std::string(_filename.substr(0,dot_pos+1));
Jan Möbius's avatar
Jan Möbius committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
  }

  bool result = read(in, _bi, _opt);

  in.close();
  return result;
}

//-----------------------------------------------------------------------------

bool
_OBJReader_::
read_material(std::fstream& _in)
{
  std::string line;
  std::string keyWrd;
161
  std::string textureName;
Jan Möbius's avatar
Jan Möbius committed
162

Martin Schultz's avatar
Martin Schultz committed
163
  std::stringstream  stream;
164

Jan Möbius's avatar
Jan Möbius committed
165 166 167 168
  std::string key;
  Material    mat;
  float       f1,f2,f3;
  bool        indef = false;
169
  int         textureId = 1;
Jan Möbius's avatar
Jan Möbius committed
170 171


Martin Habbecke's avatar
Martin Habbecke committed
172
  materials_.clear();
Jan Möbius's avatar
Jan Möbius committed
173 174 175 176 177 178 179 180 181 182 183 184 185
  mat.cleanup();

  while( _in && !_in.eof() )
  {
    std::getline(_in,line);
    if ( _in.bad() ){
      omerr() << "  Warning! Could not read file properly!\n";
      return false;
    }

    if ( line.empty() )
      continue;

186 187
    stream.str(line);
    stream.clear();
Jan Möbius's avatar
Jan Möbius committed
188 189 190

    stream >> keyWrd;

191
    if( ( isspace(line[0]) && line[0] != '\t' ) || line[0] == '#' )
Jan Möbius's avatar
Jan Möbius committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
    {
      if (indef && !key.empty() && mat.is_valid())
      {
        materials_[key] = mat;
        mat.cleanup();
      }
    }

    else if (keyWrd == "newmtl") // begin new material definition
    {
      stream >> key;
      indef = true;
    }

    else if (keyWrd == "Kd") // diffuse color
    {
      stream >> f1; stream >> f2; stream >> f3;

      if( !stream.fail() )
        mat.set_Kd(f1,f2,f3);
    }

    else if (keyWrd == "Ka") // ambient color
    {
      stream >> f1; stream >> f2; stream >> f3;

      if( !stream.fail() )
        mat.set_Ka(f1,f2,f3);
    }

    else if (keyWrd == "Ks") // specular color
    {
      stream >> f1; stream >> f2; stream >> f3;

      if( !stream.fail() )
        mat.set_Ks(f1,f2,f3);
    }
#if 0
    else if (keyWrd == "illum") // diffuse/specular shading model
    {
      ; // just skip this
    }

    else if (keyWrd == "Ns") // Shininess [0..200]
    {
      ; // just skip this
    }

    else if (keyWrd == "map_") // map images
    {
      // map_Ks, specular map
      // map_Ka, ambient map
      // map_Bump, bump map
      // map_d,  opacity map
      ; // just skip this
    }
#endif
249
    else if (keyWrd == "map_Kd" ) {
250 251
      // Get the rest of the line, removing leading or trailing spaces
      // This will define the filename of the texture
252 253
      std::getline(stream,textureName);
      trimString(textureName);
254 255
      if ( ! textureName.empty() )
        mat.set_map_Kd( textureName, textureId++ );
256
    }
Jan Möbius's avatar
Jan Möbius committed
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
    else if (keyWrd == "Tr") // transparency value
    {
      stream >> f1;

      if( !stream.fail() )
        mat.set_Tr(f1);
    }
    else if (keyWrd == "d") // transparency value
    {
      stream >> f1;

      if( !stream.fail() )
        mat.set_Tr(f1);
    }

    if ( _in && indef && mat.is_valid() && !key.empty())
      materials_[key] = mat;
  }
  return true;
}
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
//-----------------------------------------------------------------------------

bool
_OBJReader_::
read_vertices(std::istream& _in, BaseImporter& _bi, Options& _opt,
              std::vector<Vec3f> & normals,
              std::vector<Vec3f> & colors,
              std::vector<Vec3f> & texcoords3d,
              std::vector<Vec2f> & texcoords,
              std::vector<VertexHandle> & vertexHandles,
              Options & fileOptions)
{
    float x, y, z, u, v, w;
    float r, g, b;

    std::string line;
    std::string keyWrd;

    std::stringstream stream;


    // Options supplied by the user
    const Options & userOptions = _opt;

    while( _in && !_in.eof() )
    {
        std::getline(_in,line);
        if ( _in.bad() ){
          omerr() << "  Warning! Could not read file properly!\n";
          return false;
        }

        // Trim Both leading and trailing spaces
        trimString(line);

        // comment
        if ( line.size() == 0 || line[0] == '#' || isspace(line[0]) ) {
          continue;
        }

        stream.str(line);
        stream.clear();

        stream >> keyWrd;

        // vertex
        if (keyWrd == "v")
        {
          stream >> x; stream >> y; stream >> z;

          if ( !stream.fail() )
          {
            vertexHandles.push_back(_bi.add_vertex(OpenMesh::Vec3f(x,y,z)));
            stream >> r; stream >> g; stream >> b;

            if ( !stream.fail() )
            {
              if (  userOptions.vertex_has_color() ) {
                fileOptions += Options::VertexColor;
                colors.push_back(OpenMesh::Vec3f(r,g,b));
              }
            }
          }
        }

        // texture coord
        else if (keyWrd == "vt")
        {
          stream >> u; stream >> v;

          if ( !stream.fail()  ){

            if ( userOptions.vertex_has_texcoord() || userOptions.face_has_texcoord() ) {
              texcoords.push_back(OpenMesh::Vec2f(u, v));

              // Can be used for both!
              fileOptions += Options::VertexTexCoord;
              fileOptions += Options::FaceTexCoord;

              // try to read the w component as it is optional
              stream >> w;
              if ( !stream.fail()  )
                  texcoords3d.push_back(OpenMesh::Vec3f(u, v, w));

            }

          }else{
            omerr() << "Only single 2D or 3D texture coordinate per vertex"
                  << "allowed!" << std::endl;
            return false;
          }
        }

        // color per vertex
        else if (keyWrd == "vc")
        {
          stream >> r; stream >> g; stream >> b;

          if ( !stream.fail()   ){
            if ( userOptions.vertex_has_color() ) {
              colors.push_back(OpenMesh::Vec3f(r,g,b));
              fileOptions += Options::VertexColor;
            }
          }
        }

        // normal
        else if (keyWrd == "vn")
        {
          stream >> x; stream >> y; stream >> z;

          if ( !stream.fail() ) {
            if (userOptions.vertex_has_normal() ){
              normals.push_back(OpenMesh::Vec3f(x,y,z));
              fileOptions += Options::VertexNormal;
            }
          }
        }
    }

    return true;
}
Jan Möbius's avatar
Jan Möbius committed
399 400 401 402 403

//-----------------------------------------------------------------------------

bool
_OBJReader_::
404
read(std::istream& _in, BaseImporter& _bi, Options& _opt)
Jan Möbius's avatar
Jan Möbius committed
405 406 407 408
{
  std::string line;
  std::string keyWrd;

409
  std::vector<Vec3f>        normals;
410
  std::vector<Vec3f>        colors;
411 412
  std::vector<Vec3f>        texcoords3d;
  std::vector<Vec2f>        texcoords;
413
  std::vector<VertexHandle> vertexHandles;
414

415 416 417 418
  BaseImporter::VHandles    vhandles;
  std::vector<Vec3f>        face_texcoords3d;
  std::vector<Vec2f>        face_texcoords;

419
  std::string               matname;
Jan Möbius's avatar
Jan Möbius committed
420

Martin Schultz's avatar
Martin Schultz committed
421
  std::stringstream         stream, lineData, tmp;
422

Jan Möbius's avatar
Jan Möbius committed
423

424 425 426 427 428 429
  // Options supplied by the user
  Options userOptions = _opt;

  // Options collected via file parsing
  Options fileOptions;

430 431 432 433 434 435 436 437 438 439
  // pass 1: read vertices
  if ( !read_vertices(_in, _bi, _opt,
                      normals, colors, texcoords3d, texcoords,
                      vertexHandles, fileOptions) ){
      return false;
  }

  // reset stream for second pass
  _in.clear();
  _in.seekg(0, std::ios::beg);
440

441 442 443
  int nCurrentPositions = 0,
      nCurrentTexcoords = 0,
      nCurrentNormals   = 0;
Max Limper's avatar
Max Limper committed
444
  
Max Limper's avatar
Max Limper committed
445
  // pass 2: read faces
Jan Möbius's avatar
Jan Möbius committed
446 447 448 449 450 451 452 453
  while( _in && !_in.eof() )
  {
    std::getline(_in,line);
    if ( _in.bad() ){
      omerr() << "  Warning! Could not read file properly!\n";
      return false;
    }

Jan Möbius's avatar
Jan Möbius committed
454
    // Trim Both leading and trailing spaces
455
    trimString(line);
Jan Möbius's avatar
Jan Möbius committed
456

Jan Möbius's avatar
Jan Möbius committed
457 458 459 460 461
    // comment
    if ( line.size() == 0 || line[0] == '#' || isspace(line[0]) ) {
      continue;
    }

462 463
    stream.str(line);
    stream.clear();
Jan Möbius's avatar
Jan Möbius committed
464 465 466 467 468 469 470 471

    stream >> keyWrd;

    // material file
    if (keyWrd == "mtllib")
    {
      std::string matFile;

Jan Möbius's avatar
Jan Möbius committed
472 473 474 475
      // Get the rest of the line, removing leading or trailing spaces
      // This will define the filename of the texture
      std::getline(stream,matFile);
      trimString(matFile);
Jan Möbius's avatar
Jan Möbius committed
476 477 478

      matFile = path_ + matFile;

Jan Möbius's avatar
Jan Möbius committed
479
      //omlog() << "Load material file " << matFile << std::endl;
Jan Möbius's avatar
Jan Möbius committed
480 481 482 483 484 485

      std::fstream matStream( matFile.c_str(), std::ios_base::in );

      if ( matStream ){

        if ( !read_material( matStream ) )
486
            omerr() << "  Warning! Could not read file properly!\n";
Jan Möbius's avatar
Jan Möbius committed
487 488 489
        matStream.close();

      }else
490
          omerr() << "  Warning! Material file '" << matFile << "' not found!\n";
491

Jan Möbius's avatar
Jan Möbius committed
492
      //omlog() << "  " << materials_.size() << " materials loaded.\n";
493

Jan Möbius's avatar
Jan Möbius committed
494
      for ( MaterialList::iterator material = materials_.begin(); material != materials_.end(); ++material )
495
      {
Jan Möbius's avatar
Jan Möbius committed
496 497 498
        // Save the texture information in a property
        if ( (*material).second.has_map_Kd() )
          _bi.add_texture_information( (*material).second.map_Kd_index() , (*material).second.map_Kd() );
499 500
      }

Jan Möbius's avatar
Jan Möbius committed
501 502 503 504 505 506 507 508 509 510 511 512 513
    }

    // usemtl
    else if (keyWrd == "usemtl")
    {
      stream >> matname;
      if (materials_.find(matname)==materials_.end())
      {
        omerr() << "Warning! Material '" << matname
              << "' not defined in material file.\n";
        matname="";
      }
    }
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
    
    // track current number of parsed vertex attributes,
    // to allow for OBJs negative indices
    else if (keyWrd == "v")
    {
        ++nCurrentPositions;
    }
    else if (keyWrd == "vt")
    {
        ++nCurrentTexcoords;
    }
    else if (keyWrd == "vn")
    {
        ++nCurrentNormals;
    }
Jan Möbius's avatar
Jan Möbius committed
529

530
    // faces
Jan Möbius's avatar
Jan Möbius committed
531 532 533 534 535 536
    else if (keyWrd == "f")
    {
      int component(0), nV(0);
      int value;

      vhandles.clear();
537
      face_texcoords.clear();
538
      face_texcoords3d.clear();
Jan Möbius's avatar
Jan Möbius committed
539 540 541 542

      // read full line after detecting a face
      std::string faceLine;
      std::getline(stream,faceLine);
543 544
      lineData.str( faceLine );
      lineData.clear();
Jan Möbius's avatar
Jan Möbius committed
545

546 547 548
      FaceHandle fh;
      BaseImporter::VHandles faceVertices;

Jan Möbius's avatar
Jan Möbius committed
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
      // work on the line until nothing left to read
      while ( !lineData.eof() )
      {
        // read one block from the line ( vertex/texCoord/normal )
        std::string vertex;
        lineData >> vertex;

        do{

          //get the component (vertex/texCoord/normal)
          size_t found=vertex.find("/");

          // parts are seperated by '/' So if no '/' found its the last component
          if( found != std::string::npos ){

            // read the index value
565 566
            tmp.str( vertex.substr(0,found) );
            tmp.clear();
Jan Möbius's avatar
Jan Möbius committed
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588

            // If we get an empty string this property is undefined in the file
            if ( vertex.substr(0,found).empty() ) {
              // Switch to next field
              vertex = vertex.substr(found+1);

              // Now we are at the next component
              ++component;

              // Skip further processing of this component
              continue;
            }

            // Read current value
            tmp >> value;

            // remove the read part from the string
            vertex = vertex.substr(found+1);

          } else {

            // last component of the vertex, read it.
589 590
            tmp.str( vertex );
            tmp.clear();
Jan Möbius's avatar
Jan Möbius committed
591 592
            tmp >> value;

Jan Möbius's avatar
Jan Möbius committed
593 594 595
            // Clear vertex after finished reading the line
            vertex="";

Jan Möbius's avatar
Jan Möbius committed
596 597 598 599 600 601 602 603 604 605 606
            // Nothing to read here ( garbage at end of line )
            if ( tmp.fail() ) {
              continue;
            }
          }

          // store the component ( each component is referenced by the index here! )
          switch (component)
          {
            case 0: // vertex
              if ( value < 0 ) {
607 608 609
                // Calculation of index :
                // -1 is the last vertex in the list
                // As obj counts from 1 and not zero add +1
610
                value = nCurrentPositions + value + 1;
Jan Möbius's avatar
Jan Möbius committed
611
              }
612
              // Obj counts from 1 and not zero .. array counts from zero therefore -1
Jan Möbius's avatar
Jan Möbius committed
613
              vhandles.push_back(VertexHandle(value-1));
614
              faceVertices.push_back(VertexHandle(value-1));
615 616 617 618 619 620 621 622
              if (fileOptions.vertex_has_color()) {
                if ((unsigned int)(value - 1) < colors.size()) {
                  _bi.set_color(vhandles.back(), colors[value - 1]);
                }
                else {
                  omerr() << "Error setting vertex color" << std::endl;
                }
              }                  
Jan Möbius's avatar
Jan Möbius committed
623
              break;
624
	      
Jan Möbius's avatar
Jan Möbius committed
625 626
            case 1: // texture coord
              if ( value < 0 ) {
627 628 629
                // Calculation of index :
                // -1 is the last vertex in the list
                // As obj counts from 1 and not zero add +1
630
                value = nCurrentTexcoords + value + 1;
Jan Möbius's avatar
Jan Möbius committed
631 632
              }
              assert(!vhandles.empty());
633 634 635 636 637 638 639


              if ( fileOptions.vertex_has_texcoord() && userOptions.vertex_has_texcoord() ) {

                if (!texcoords.empty() && (unsigned int) (value - 1) < texcoords.size()) {
                  // Obj counts from 1 and not zero .. array counts from zero therefore -1
                  _bi.set_texcoord(vhandles.back(), texcoords[value - 1]);
640 641
                  if(!texcoords3d.empty() && (unsigned int) (value -1) < texcoords3d.size())
                    _bi.set_texcoord(vhandles.back(), texcoords3d[value - 1]);
642 643 644 645 646 647 648 649 650 651
                } else {
                  omerr() << "Error setting Texture coordinates" << std::endl;
                }

                }

                if (fileOptions.face_has_texcoord() && userOptions.face_has_texcoord() ) {

                  if (!texcoords.empty() && (unsigned int) (value - 1) < texcoords.size()) {
                    face_texcoords.push_back( texcoords[value-1] );
652 653
                    if(!texcoords3d.empty() && (unsigned int) (value -1) < texcoords3d.size())
                      face_texcoords3d.push_back( texcoords3d[value-1] );
654 655 656 657 658
                  } else {
                    omerr() << "Error setting Texture coordinates" << std::endl;
                  }
                }

659

Jan Möbius's avatar
Jan Möbius committed
660 661 662 663
              break;

            case 2: // normal
              if ( value < 0 ) {
664 665 666
                // Calculation of index :
                // -1 is the last vertex in the list
                // As obj counts from 1 and not zero add +1
667
                value = nCurrentNormals + value + 1;
Jan Möbius's avatar
Jan Möbius committed
668
              }
669

670
              // Obj counts from 1 and not zero .. array counts from zero therefore -1
671
              if (fileOptions.vertex_has_normal() ) {
672 673 674 675 676 677 678
                assert(!vhandles.empty());                
                if ((unsigned int)(value - 1) < normals.size()) {
                    _bi.set_normal(vhandles.back(), normals[value - 1]);
                }
                else {
                    omerr() << "Error setting vertex normal" << std::endl;
                }                
679
              }
Jan Möbius's avatar
Jan Möbius committed
680 681 682 683 684 685
              break;
          }

          // Prepare for reading next component
          ++component;

Jan Möbius's avatar
Jan Möbius committed
686 687
          // Read until line does not contain any other info
        } while ( !vertex.empty() );
Jan Möbius's avatar
Jan Möbius committed
688 689 690 691

        component = 0;
        nV++;

692
      }
Jan Möbius's avatar
Jan Möbius committed
693

694 695
      // note that add_face can possibly triangulate the faces, which is why we have to
      // store the current number of faces first
Jan Möbius's avatar
Jan Möbius committed
696
      size_t n_faces = _bi.n_faces();
697 698 699 700 701
      remove_duplicated_vertices(faceVertices);

      //A minimum of three vertices are required.
      if (faceVertices.size() > 2)
        fh = _bi.add_face(faceVertices);
Jan Möbius's avatar
Jan Möbius committed
702

703
      if (!vhandles.empty() && fh.is_valid() )
704
      {
705
        _bi.add_face_texcoords(fh, vhandles[0], face_texcoords);
706 707
        _bi.add_face_texcoords(fh, vhandles[0], face_texcoords3d);
      }
708

709
      if ( !matname.empty()  )
Jan Möbius's avatar
Jan Möbius committed
710 711 712 713
      {
        std::vector<FaceHandle> newfaces;

        for( size_t i=0; i < _bi.n_faces()-n_faces; ++i )
714
          newfaces.push_back(FaceHandle(int(n_faces+i)));
Jan Möbius's avatar
Jan Möbius committed
715

716 717 718 719 720
        Material& mat = materials_[matname];

        if ( mat.has_Kd() ) {
          Vec3uc fc = color_cast<Vec3uc, Vec3f>(mat.Kd());

721 722 723 724
          if ( userOptions.face_has_color()) {

            for (std::vector<FaceHandle>::iterator it = newfaces.begin(); it != newfaces.end(); ++it)
              _bi.set_color(*it, fc);
725

726 727
            fileOptions += Options::FaceColor;
          }
728 729 730 731
        }

        // Set the texture index in the face index property
        if ( mat.has_map_Kd() ) {
Jan Möbius's avatar
Jan Möbius committed
732

733 734 735 736 737 738 739 740
          if (userOptions.face_has_texcoord()) {

            for (std::vector<FaceHandle>::iterator it = newfaces.begin(); it != newfaces.end(); ++it)
              _bi.set_face_texindex(*it, mat.map_Kd_index());

            fileOptions += Options::FaceTexCoord;

          }
Jan Möbius's avatar
Jan Möbius committed
741

742
        } else {
743

744
          // If we don't have the info, set it to no texture
745 746 747 748 749 750
          if (userOptions.face_has_texcoord()) {

            for (std::vector<FaceHandle>::iterator it = newfaces.begin(); it != newfaces.end(); ++it)
              _bi.set_face_texindex(*it, 0);

          }
751
        }
Jan Möbius's avatar
Jan Möbius committed
752

753 754 755 756
      } else {
        std::vector<FaceHandle> newfaces;

        for( size_t i=0; i < _bi.n_faces()-n_faces; ++i )
757
          newfaces.push_back(FaceHandle(int(n_faces+i)));
758 759

        // Set the texture index to zero as we don't have any information
760 761 762
        if ( userOptions.face_has_texcoord() )
          for (std::vector<FaceHandle>::iterator it = newfaces.begin(); it != newfaces.end(); ++it)
            _bi.set_face_texindex(*it, 0);
Jan Möbius's avatar
Jan Möbius committed
763
      }
764

Jan Möbius's avatar
Jan Möbius committed
765
    }
766

Jan Möbius's avatar
Jan Möbius committed
767 768
  }

769 770
  // If we do not have any faces,
  // assume this is a point cloud and read the normals and colors directly
771
  if (_bi.n_faces() == 0)
772
  {
773
    int i = 0;
774 775
    // add normal per vertex

776 777 778 779 780 781
    if (normals.size() == _bi.n_vertices()) {
      if ( fileOptions.vertex_has_normal() && userOptions.vertex_has_normal() ) {
        for (std::vector<VertexHandle>::iterator it = vertexHandles.begin(); it != vertexHandles.end(); ++it, i++)
          _bi.set_normal(*it, normals[i]);
      }
    }
782 783

    // add color per vertex
784 785 786 787 788
    i = 0;
    if (colors.size() >= _bi.n_vertices())
      if (fileOptions.vertex_has_color() && userOptions.vertex_has_color()) {
        for (std::vector<VertexHandle>::iterator it = vertexHandles.begin(); it != vertexHandles.end(); ++it, i++)
          _bi.set_color(*it, colors[i]);
789 790 791 792
      }

  }

Jan Möbius's avatar
Jan Möbius committed
793 794 795
  // Return, what we actually read
  _opt = fileOptions;

Jan Möbius's avatar
Jan Möbius committed
796 797 798 799 800 801 802 803
  return true;
}


//=============================================================================
} // namespace IO
} // namespace OpenMesh
//=============================================================================