OFFReader.cc 17.4 KB
Newer Older
Jan Möbius's avatar
Jan Möbius committed
1 2 3
/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
4
 *      Copyright (C) 2001-2009 by Computer Graphics Group, RWTH Aachen      *
Jan Möbius's avatar
Jan Möbius committed
5 6
 *                           www.openmesh.org                                *
 *                                                                           *
7
 *---------------------------------------------------------------------------*
8
 *  This file is part of OpenMesh.                                           *
Jan Möbius's avatar
Jan Möbius committed
9
 *                                                                           *
10
 *  OpenMesh is free software: you can redistribute it and/or modify         *
11 12 13 14
 *  it under the terms of the GNU Lesser General Public License as           *
 *  published by the Free Software Foundation, either version 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
Jan Möbius's avatar
Jan Möbius committed
15
 *                                                                           *
16 17 18 19 20 21 22
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
Jan Möbius's avatar
Jan Möbius committed
23
 *                                                                           *
24 25 26 27
 *  OpenMesh 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 Lesser General Public License for more details.                      *
Jan Möbius's avatar
Jan Möbius committed
28
 *                                                                           *
29 30 31 32
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
33
\*===========================================================================*/
34 35

/*===========================================================================*\
36
 *                                                                           *
37 38
 *   $Revision$                                                         *
 *   $Date$                   *
Jan Möbius's avatar
Jan Möbius committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
 *                                                                           *
\*===========================================================================*/


#define LINE_LEN 4096


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

// OpenMesh
#include <OpenMesh/Core/System/config.h>
#include <OpenMesh/Core/System/omstream.hh>
#include <OpenMesh/Core/IO/reader/OFFReader.hh>
#include <OpenMesh/Core/IO/importer/BaseImporter.hh>
#include <OpenMesh/Core/IO/IOManager.hh>
#include <OpenMesh/Core/Utils/color_cast.hh>
// #include <OpenMesh/Core/IO/BinaryHelper.hh>

#include <OpenMesh/Core/IO/SR_store.hh>

//STL
60 61
#include <iostream>
#include <ios>
Jan Möbius's avatar
Jan Möbius committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
#include <fstream>
#include <memory>

#ifndef WIN32
#include <string.h>
#endif

//=== NAMESPACES ==============================================================


namespace OpenMesh {
namespace IO {


//=============================================================================

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


_OFFReader_  __OFFReaderInstance;
_OFFReader_&  OFFReader() { return __OFFReaderInstance; }


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



89 90 91
_OFFReader_::_OFFReader_()
{
  IOManager().register_module(this);
Jan Möbius's avatar
Jan Möbius committed
92 93 94 95 96 97
}


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


98 99
bool
_OFFReader_::read(const std::string& _filename, BaseImporter& _bi,
Jan Möbius's avatar
Jan Möbius committed
100 101
                  Options& _opt)
{
102 103
  std::ifstream ifile(_filename.c_str(), (options_.is_binary() ? std::ios::binary | std::ios::in
                                                           : std::ios::in) );
Jan Möbius's avatar
Jan Möbius committed
104

105
  if (!ifile.is_open() || !ifile.good())
Jan Möbius's avatar
Jan Möbius committed
106
  {
107
    omerr() << "[OFFReader] : cannot not open file "
Jan Möbius's avatar
Jan Möbius committed
108 109
	  << _filename
	  << std::endl;
110

Jan Möbius's avatar
Jan Möbius committed
111 112 113
    return false;
  }

114
  assert(ifile);
Jan Möbius's avatar
Jan Möbius committed
115

116
  bool result = read(ifile, _bi, _opt);
Jan Möbius's avatar
Jan Möbius committed
117

118
  ifile.close();
Jan Möbius's avatar
Jan Möbius committed
119 120 121 122 123 124
  return result;
}

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


125 126
bool
_OFFReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt )
Jan Möbius's avatar
Jan Möbius committed
127
{
128 129 130 131 132 133 134
   if (!_in.good())
   {
     omerr() << "[OMReader] : cannot not use stream "
       << std::endl;
     return false;
   }

Jan Möbius's avatar
Jan Möbius committed
135 136
   // filter relevant options for reading
   bool swap = _opt.check( Options::Swap );
137

Jan Möbius's avatar
Jan Möbius committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163

   userOptions_ = _opt;

   // build options to be returned
   _opt.clear();

   if (options_.vertex_has_normal() && userOptions_.vertex_has_normal())     _opt += Options::VertexNormal;
   if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) _opt += Options::VertexTexCoord;
   if (options_.vertex_has_color() && userOptions_.vertex_has_color())       _opt += Options::VertexColor;
   if (options_.face_has_color() && userOptions_.face_has_color())           _opt += Options::FaceColor;
   if (options_.is_binary())                                                 _opt += Options::Binary;

   //force user-choice for the alpha value when reading binary
   if ( options_.is_binary() && userOptions_.color_has_alpha() )
     options_ += Options::ColorAlpha;

    return (options_.is_binary() ?
 	   read_binary(_in, _bi, swap) :
	   read_ascii(_in, _bi));

}



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

164 165
bool
_OFFReader_::read_ascii(std::istream& _in, BaseImporter& _bi) const
Jan Möbius's avatar
Jan Möbius committed
166 167 168 169
{


omlog() << "[OFFReader] : read ascii file\n";
170

Jan Möbius's avatar
Jan Möbius committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
  unsigned int            i, j, k, l, idx;
  unsigned int            nV, nF, dummy;
  OpenMesh::Vec3f         v, n;
  OpenMesh::Vec2f         t;
  OpenMesh::Vec3i         c3;
  OpenMesh::Vec3f         c3f;
  OpenMesh::Vec4i         c4;
  OpenMesh::Vec4f         c4f;
  BaseImporter::VHandles  vhandles;
  VertexHandle            vh;

  // read header line
  std::string header;
  std::getline(_in,header);

  // + #Vertice, #Faces, #Edges
  _in >> nV;
  _in >> nF;
  _in >> dummy;

  _bi.reserve(nV, 3*nV, nF);

  // read vertices: coord [hcoord] [normal] [color] [texcoord]
  for (i=0; i<nV && !_in.eof(); ++i)
  {
    // Always read VERTEX
    _in >> v[0]; _in >> v[1]; _in >> v[2];
198

Jan Möbius's avatar
Jan Möbius committed
199
    vh = _bi.add_vertex(v);
200

Jan Möbius's avatar
Jan Möbius committed
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
    //perhaps read NORMAL
    if ( options_.vertex_has_normal() ){

      _in >> n[0]; _in >> n[1]; _in >> n[2];

      if ( userOptions_.vertex_has_normal() )
        _bi.set_normal(vh, n);
    }

    //take the rest of the line and check how colors are defined
    std::string line;
    std::getline(_in,line);

    int colorType = getColorType(line, options_.vertex_has_texcoord() );

    std::stringstream stream( line );

    //perhaps read COLOR
    if ( options_.vertex_has_color() ){

      std::string trash;

      switch (colorType){
        case 0 : break; //no color
        case 1 : stream >> trash; break; //one int (isn't handled atm)
        case 2 : stream >> trash; stream >> trash; break; //corrupt format (ignore)
        // rgb int
        case 3 : stream >> c3[0];  stream >> c3[1];  stream >> c3[2];
            if ( userOptions_.vertex_has_color() )
              _bi.set_color( vh, Vec3uc( c3 ) );
            break;
        // rgba int
        case 4 : stream >> c4[0];  stream >> c4[1];  stream >> c4[2]; stream >> c4[3];
            if ( userOptions_.vertex_has_color() )
              _bi.set_color( vh, Vec4uc( c4 ) );
            break;
        // rgb floats
        case 5 : stream >> c3f[0];  stream >> c3f[1];  stream >> c3f[2];
            if ( userOptions_.vertex_has_color() )
              _bi.set_color( vh, color_cast<Vec3uc, Vec3f>(c3f) );
            break;
        // rgba floats
        case 6 : stream >> c4f[0];  stream >> c4f[1];  stream >> c4f[2]; stream >> c4f[3];
            if ( userOptions_.vertex_has_color() )
              _bi.set_color( vh, color_cast<Vec4uc, Vec4f>(c4f) );
            break;

248
        default:
Jan Möbius's avatar
Jan Möbius committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
            std::cerr << "Error in file format (colorType = " << colorType << ")\n";
      }
    }
    //perhaps read TEXTURE COORDs
    if ( options_.vertex_has_texcoord() ){
      stream >> t[0]; stream >> t[1];
      if ( userOptions_.vertex_has_texcoord() )
        _bi.set_texcoord(vh, t);
    }
  }

  // faces
  // #N <v1> <v2> .. <v(n-1)> [color spec]
  for (i=0; i<nF; ++i)
  {
    // nV = number of Vertices for current face
    _in >> nV;

    if (nV == 3)
    {
      vhandles.resize(3);
      _in >> j;
      _in >> k;
      _in >> l;

      vhandles[0] = VertexHandle(j);
      vhandles[1] = VertexHandle(k);
      vhandles[2] = VertexHandle(l);
    }
278
    else
Jan Möbius's avatar
Jan Möbius committed
279 280 281 282 283 284 285 286
    {
      vhandles.clear();
      for (j=0; j<nV; ++j)
      {
         _in >> idx;
         vhandles.push_back(VertexHandle(idx));
      }
    }
287

Jan Möbius's avatar
Jan Möbius committed
288 289 290 291 292 293 294 295 296 297 298
    FaceHandle fh = _bi.add_face(vhandles);

    //perhaps read face COLOR
    if ( options_.face_has_color() ){

      //take the rest of the line and check how colors are defined
      std::string line;
      std::getline(_in,line);

      int colorType = getColorType(line, false );

299
      std::stringstream stream( line );
Jan Möbius's avatar
Jan Möbius committed
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

      std::string trash;

      switch (colorType){
        case 0 : break; //no color
        case 1 : stream >> trash; break; //one int (isn't handled atm)
        case 2 : stream >> trash; stream >> trash; break; //corrupt format (ignore)
        // rgb int
        case 3 : stream >> c3[0];  stream >> c3[1];  stream >> c3[2];
            if ( userOptions_.face_has_color() )
              _bi.set_color( fh, Vec3uc( c3 ) );
            break;
        // rgba int
        case 4 : stream >> c4[0];  stream >> c4[1];  stream >> c4[2]; stream >> c4[3];
            if ( userOptions_.face_has_color() )
              _bi.set_color( fh, Vec4uc( c4 ) );
            break;
        // rgb floats
        case 5 : stream >> c3f[0];  stream >> c3f[1];  stream >> c3f[2];
            if ( userOptions_.face_has_color() )
              _bi.set_color( fh, color_cast<Vec3uc, Vec3f>(c3f) );
            break;
        // rgba floats
        case 6 : stream >> c4f[0];  stream >> c4f[1];  stream >> c4f[2]; stream >> c4f[3];
            if ( userOptions_.face_has_color() )
              _bi.set_color( fh, color_cast<Vec4uc, Vec4f>(c4f) );
            break;

328
        default:
Jan Möbius's avatar
Jan Möbius committed
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
            std::cerr << "Error in file format (colorType = " << colorType << ")\n";
      }
    }
  }

  // File was successfully parsed.
  return true;
}


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

int _OFFReader_::getColorType(std::string& _line, bool _texCoordsAvailable) const
{
/*
  0 : no Color
  1 : one int (e.g colormap index)
  2 : two items (error!)
  3 : 3 ints
  4 : 3 ints
  5 : 3 floats
  6 : 4 floats

*/
	// Check if we have any additional information here
	if ( _line.size() < 1 )
		return 0;

    //first remove spaces at start/end of the line
    while (_line[0] == ' ')
      _line = _line.substr(1);
    while (_line[ _line.length()-1 ] == ' ')
      _line = _line.substr(0, _line.length()-2);

    //count the remaining items in the line
    size_t found;
    int count = 0;

    found=_line.find_first_of(" ");
    while (found!=std::string::npos){
      count++;
      found=_line.find_first_of(" ",found+1);
    }

    if (_line != "") count++;

    if (_texCoordsAvailable) count -= 2;

    if (count == 3 || count == 4){
      //get first item
      found = _line.find(" ");
      std::string c1 = _line.substr (0,found);
381

Jan Möbius's avatar
Jan Möbius committed
382 383 384 385 386 387 388 389 390 391
      if (c1.find(".") != std::string::npos){
        if (count == 3)
          count = 5;
        else
          count = 6;
      }
    }
  return count;
}

392
void _OFFReader_::readValue(std::istream& _in, float& _value) const{
Jan Möbius's avatar
Jan Möbius committed
393 394 395 396 397 398
  float32_t tmp;

  restore( _in , tmp, false ); //assuming LSB byte order
  _value = tmp;
}

399
void _OFFReader_::readValue(std::istream& _in, int& _value) const{
Jan Möbius's avatar
Jan Möbius committed
400 401 402 403 404 405
  uint32_t tmp;

  restore( _in , tmp, false ); //assuming LSB byte order
  _value = tmp;
}

406
void _OFFReader_::readValue(std::istream& _in, unsigned int& _value) const{
Jan Möbius's avatar
Jan Möbius committed
407 408 409 410 411 412
  uint32_t tmp;

  restore( _in , tmp, false ); //assuming LSB byte order
  _value = tmp;
}

413 414
bool
_OFFReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap*/) const
Jan Möbius's avatar
Jan Möbius committed
415 416
{
  omlog() << "[OFFReader] : read binary file\n";
417

Jan Möbius's avatar
Jan Möbius committed
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
  unsigned int            i, j, k, l, idx;
  unsigned int            nV, nF, dummy;
  OpenMesh::Vec3f         v, n;
  OpenMesh::Vec3i         c;
  OpenMesh::Vec4i         cA;
  OpenMesh::Vec2f         t;
  BaseImporter::VHandles  vhandles;
  VertexHandle            vh;

  // read header line
  std::string header;
  std::getline(_in,header);

  // + #Vertice, #Faces, #Edges
  readValue(_in, nV);
  readValue(_in, nF);
  readValue(_in, dummy);

  _bi.reserve(nV, 3*nV, nF);

438
  // read vertices: coord [hcoord] [normal] [color] [texcoord]
Jan Möbius's avatar
Jan Möbius committed
439 440 441 442 443 444
  for (i=0; i<nV && !_in.eof(); ++i)
  {
    // Always read Vertex
    readValue(_in, v[0]);
    readValue(_in, v[1]);
    readValue(_in, v[2]);
445

Jan Möbius's avatar
Jan Möbius committed
446
    vh = _bi.add_vertex(v);
447

Jan Möbius's avatar
Jan Möbius committed
448 449 450 451 452 453 454 455
    if ( options_.vertex_has_normal() ) {
      readValue(_in, n[0]);
      readValue(_in, n[1]);
      readValue(_in, n[2]);

      if ( userOptions_.vertex_has_normal() )
        _bi.set_normal(vh, n);
    }
456

Jan Möbius's avatar
Jan Möbius committed
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
    if ( options_.vertex_has_color() ) {
      //with alpha
      if ( options_.color_has_alpha() ){
        readValue(_in, cA[0]);
        readValue(_in, cA[1]);
        readValue(_in, cA[2]);
        readValue(_in, cA[3]);

        if ( userOptions_.vertex_has_color() )
          _bi.set_color( vh, Vec4uc( cA ) );
      }else{
        //without alpha
        readValue(_in, c[0]);
        readValue(_in, c[1]);
        readValue(_in, c[2]);

        if ( userOptions_.vertex_has_color() )
          _bi.set_color( vh, Vec3uc( c ) );
      }
    }
477

Jan Möbius's avatar
Jan Möbius committed
478 479 480 481 482 483 484 485
    if ( options_.vertex_has_texcoord()) {
      readValue(_in, t[0]);
      readValue(_in, t[1]);

      if ( userOptions_.vertex_has_texcoord() )
        _bi.set_texcoord(vh, t);
    }
  }
486

Jan Möbius's avatar
Jan Möbius committed
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
  // faces
  // #N <v1> <v2> .. <v(n-1)> [color spec]
  // So far color spec is unsupported!
  for (i=0; i<nF; ++i)
  {
    readValue(_in, nV);


    if (nV == 3)
    {
      vhandles.resize(3);
      readValue(_in, j);
      readValue(_in, k);
      readValue(_in, l);

      vhandles[0] = VertexHandle(j);
      vhandles[1] = VertexHandle(k);
      vhandles[2] = VertexHandle(l);
    }
506
    else
Jan Möbius's avatar
Jan Möbius committed
507 508 509 510 511 512 513 514
    {
      vhandles.clear();
      for (j=0; j<nV; ++j)
      {
         readValue(_in, idx);
         vhandles.push_back(VertexHandle(idx));
      }
    }
515

Jan Möbius's avatar
Jan Möbius committed
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
    FaceHandle fh = _bi.add_face(vhandles);

    //face color
    if ( options_.face_has_color() ) {
      //with alpha
      if ( options_.color_has_alpha() ){
        readValue(_in, cA[0]);
        readValue(_in, cA[1]);
        readValue(_in, cA[2]);
        readValue(_in, cA[3]);

        if ( userOptions_.face_has_color() )
          _bi.set_color( fh , Vec4uc( cA ) );
      }else{
        //without alpha
        readValue(_in, c[0]);
        readValue(_in, c[1]);
        readValue(_in, c[2]);

        if ( userOptions_.face_has_color() )
          _bi.set_color( fh, Vec3uc( c ) );
      }
    }

  }

  // File was successfully parsed.
  return true;

}


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


bool _OFFReader_::can_u_read(const std::string& _filename) const
{
  // !!! Assuming BaseReader::can_u_parse( std::string& )
  // does not call BaseReader::read_magic()!!!
  if (BaseReader::can_u_read(_filename))
  {
    std::ifstream ifs(_filename.c_str());
    if (ifs.is_open() && can_u_read(ifs))
    {
      ifs.close();
      return true;
562
    }
Jan Möbius's avatar
Jan Möbius committed
563 564 565 566 567 568 569
  }
  return false;
}


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

570

Jan Möbius's avatar
Jan Möbius committed
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
bool _OFFReader_::can_u_read(std::istream& _is) const
{
  options_.cleanup();

  // read 1st line
  char line[LINE_LEN], *p;
  _is.getline(line, LINE_LEN);
  p = line;

  int remainingChars = _is.gcount();

  bool vertexDimensionTooHigh = false;

  // check header: [ST][C][N][4][n]OFF BINARY

  if ( ( remainingChars > 1 ) && ( p[0] == 'S' && p[1] == 'T') )
  { options_ += Options::VertexTexCoord; p += 2; remainingChars -= 2; }

  if ( ( remainingChars > 0 ) && ( p[0] == 'C') )
  { options_ += Options::VertexColor;
    options_ += Options::FaceColor; ++p; --remainingChars; }

  if ( ( remainingChars > 0 ) && ( p[0] == 'N') )
  { options_ += Options::VertexNormal; ++p; --remainingChars; }

  if ( ( remainingChars > 0 ) && (p[0] == '4' ) )
  { vertexDimensionTooHigh = true; ++p; --remainingChars; }

  if ( ( remainingChars > 0 ) && ( p[0] == 'n') )
  { vertexDimensionTooHigh = true; ++p; --remainingChars; }
601

Jan Möbius's avatar
Jan Möbius committed
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
  if ( ( remainingChars < 3 ) || (!(p[0] == 'O' && p[1] == 'F' && p[2] == 'F')  ) )
    return false;

  p += 4;
  remainingChars -= 4;

  if ( ( remainingChars >= 6 ) && ( strncmp(p, "BINARY", 6) == 0 ) )
    options_+= Options::Binary;

  // vertex Dimensions != 3 are currently not supported
  if (vertexDimensionTooHigh)
    return false;

  return true;
}


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