git-svn-id: http://www.openmesh.org/svnrepo/OpenMesh/trunk@2 fdac6126-5c0c-442c-9429-916003d36597
629 lines
15 KiB
C++
629 lines
15 KiB
C++
/*===========================================================================*\
|
|
* *
|
|
* OpenMesh *
|
|
* Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen *
|
|
* www.openmesh.org *
|
|
* *
|
|
*---------------------------------------------------------------------------*
|
|
* *
|
|
* License *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or modify it *
|
|
* under the terms of the GNU Lesser General Public License as published *
|
|
* by the Free Software Foundation, version 2.1. *
|
|
* *
|
|
* This library 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. *
|
|
* *
|
|
* You should have received a copy of the GNU Lesser General Public *
|
|
* License along with this library; if not, write to the Free Software *
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
|
* *
|
|
\*===========================================================================*/
|
|
|
|
|
|
//== INCLUDES =================================================================
|
|
|
|
|
|
//STL
|
|
#include <fstream>
|
|
|
|
// OpenMesh
|
|
#include <OpenMesh/Core/System/config.h>
|
|
#include <OpenMesh/Core/System/omstream.hh>
|
|
#include <OpenMesh/Core/Utils/Endian.hh>
|
|
#include <OpenMesh/Core/IO/OMFormat.hh>
|
|
#include <OpenMesh/Core/IO/reader/OMReader.hh>
|
|
|
|
|
|
//=== NAMESPACES ==============================================================
|
|
|
|
|
|
namespace OpenMesh {
|
|
namespace IO {
|
|
|
|
|
|
//=== INSTANCIATE =============================================================
|
|
|
|
|
|
// register the OMReader singleton with MeshReader
|
|
_OMReader_ __OMReaderInstance;
|
|
_OMReader_& OMReader() { return __OMReaderInstance; }
|
|
|
|
|
|
|
|
//=== IMPLEMENTATION ==========================================================
|
|
|
|
|
|
_OMReader_::_OMReader_()
|
|
{
|
|
IOManager().register_module(this);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
bool
|
|
_OMReader_::read(const std::string& _filename,
|
|
BaseImporter& _bi,
|
|
Options& _opt)
|
|
{
|
|
// check whether importer can give us an OpenMesh BaseKernel
|
|
if (!_bi.kernel()) return false;
|
|
|
|
|
|
_opt += Options::Binary; // only binary format supported!
|
|
|
|
// Open file
|
|
std::ifstream ifs( _filename.c_str(), std::ios::binary );
|
|
if (!ifs.is_open())
|
|
{
|
|
omerr() << "[OMReader] : cannot not open file "
|
|
<< _filename
|
|
<< std::endl;
|
|
return false;
|
|
}
|
|
|
|
// Pass stream to read method, remember result
|
|
bool result = read(ifs, _bi, _opt);
|
|
|
|
// close input stream
|
|
ifs.close();
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
bool
|
|
_OMReader_::read(std::istream& _is, BaseImporter& _bi, Options& _opt ) const
|
|
{
|
|
// currently only binary file format is supported
|
|
_opt += Options::Binary;
|
|
|
|
return read_binary( _is, _bi, _opt );
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool
|
|
_OMReader_::read_ascii( std::istream& /* _is */, BaseImporter& /* _bi */,
|
|
Options& /* _opt */) const
|
|
{
|
|
// not supported yet!
|
|
return false;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool
|
|
_OMReader_::read_binary( std::istream& _is, BaseImporter& _bi,
|
|
Options& _opt) const
|
|
{
|
|
bool swap = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB);
|
|
|
|
// intialize byte counter
|
|
bytes_ = 0;
|
|
|
|
bytes_ += restore( _is, header_, swap );
|
|
|
|
size_t data_bytes;
|
|
|
|
while( !_is.eof() )
|
|
{
|
|
bytes_ += restore( _is, chunk_header_, swap );
|
|
|
|
if ( _is.eof() )
|
|
break;
|
|
|
|
// Is this a named property restore the name
|
|
if ( chunk_header_.name_ )
|
|
{
|
|
OMFormat::Chunk::PropertyName pn;
|
|
bytes_ += restore( _is, property_name_, swap );
|
|
}
|
|
|
|
// Read in the property data. If it is an anonymous or unknown named
|
|
// property, then skip data.
|
|
data_bytes = bytes_;
|
|
switch( chunk_header_.entity_ )
|
|
{
|
|
case OMFormat::Chunk::Entity_Vertex:
|
|
if (!read_binary_vertex_chunk( _is, _bi, _opt, swap ))
|
|
return false;
|
|
break;
|
|
case OMFormat::Chunk::Entity_Face:
|
|
if (!read_binary_face_chunk( _is, _bi, _opt, swap ))
|
|
return false;
|
|
break;
|
|
case OMFormat::Chunk::Entity_Edge:
|
|
if (!read_binary_edge_chunk( _is, _bi, _opt, swap ))
|
|
return false;
|
|
break;
|
|
case OMFormat::Chunk::Entity_Halfedge:
|
|
if (!read_binary_halfedge_chunk( _is, _bi, _opt, swap ))
|
|
return false;
|
|
break;
|
|
case OMFormat::Chunk::Entity_Mesh:
|
|
if (!read_binary_mesh_chunk( _is, _bi, _opt, swap ))
|
|
return false;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
data_bytes = bytes_ - data_bytes;
|
|
}
|
|
|
|
// File was successfully parsed.
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool
|
|
_OMReader_::can_u_read(const std::string& _filename) const
|
|
{
|
|
// !!! Assuming BaseReader::can_u_parse( std::string& )
|
|
// does not call BaseReader::read_magic()!!!
|
|
if ( this->BaseReader::can_u_read( _filename ) )
|
|
{
|
|
std::ifstream ifile( _filename.c_str() );
|
|
if ( ifile && can_u_read( ifile ) )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool
|
|
_OMReader_::can_u_read(std::istream& _is) const
|
|
{
|
|
std::vector<char> evt;
|
|
evt.reserve(20);
|
|
|
|
// read first 4 characters into a buffer
|
|
while( evt.size() < 4 )
|
|
evt.push_back( static_cast<char>(_is.get()) );
|
|
|
|
// put back all read characters
|
|
std::vector<char>::reverse_iterator it = evt.rbegin();
|
|
while (it != evt.rend() )
|
|
_is.putback( *it++ );
|
|
|
|
|
|
// evaluate header information
|
|
OMFormat::Header *hdr = (OMFormat::Header*)&evt[0];
|
|
|
|
// first two characters must be 'OM'
|
|
if (hdr->magic_[0] != 'O' || hdr->magic_[1] != 'M')
|
|
return false;
|
|
|
|
// 3rd characters defines the mesh type:
|
|
switch(hdr->mesh_)
|
|
{
|
|
case 'T': // Triangle Mesh
|
|
case 'Q': // Quad Mesh
|
|
case 'P': // Polygonal Mesh
|
|
break;
|
|
default: // ?
|
|
return false;
|
|
}
|
|
|
|
// 4th characters encodes the version
|
|
return supports( hdr->version_ );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool
|
|
_OMReader_::supports( const OMFormat::uint8 /* version */ ) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool
|
|
_OMReader_::read_binary_vertex_chunk( std::istream &_is,
|
|
BaseImporter &_bi,
|
|
Options &_opt,
|
|
bool _swap) const
|
|
{
|
|
using OMFormat::Chunk;
|
|
|
|
assert( chunk_header_.entity_ == Chunk::Entity_Vertex );
|
|
|
|
OpenMesh::Vec3f v3f;
|
|
OpenMesh::Vec2f v2f;
|
|
OpenMesh::Vec3uc v3uc; // rgb
|
|
|
|
OMFormat::Chunk::PropertyName custom_prop;
|
|
|
|
size_t vidx=0;
|
|
switch (chunk_header_.type_)
|
|
{
|
|
case Chunk::Type_Pos:
|
|
assert( OMFormat::dimensions(chunk_header_)
|
|
== size_t(OpenMesh::Vec3f::dim()) );
|
|
|
|
for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx)
|
|
{
|
|
bytes_ += vector_restore( _is, v3f, _swap );
|
|
_bi.add_vertex(v3f);
|
|
}
|
|
break;
|
|
|
|
|
|
case Chunk::Type_Normal:
|
|
assert( OMFormat::dimensions(chunk_header_)
|
|
== size_t(OpenMesh::Vec3f::dim()) );
|
|
|
|
_opt += Options::VertexNormal;
|
|
for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx)
|
|
{
|
|
bytes_ += vector_restore( _is, v3f, _swap );
|
|
_bi.set_normal(VertexHandle(vidx), v3f);
|
|
}
|
|
break;
|
|
|
|
|
|
case Chunk::Type_Texcoord:
|
|
assert( OMFormat::dimensions(chunk_header_)
|
|
== size_t(OpenMesh::Vec2f::dim()) );
|
|
|
|
_opt += Options::VertexTexCoord;
|
|
for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx)
|
|
{
|
|
bytes_ += vector_restore( _is, v2f, _swap );
|
|
_bi.set_texcoord(VertexHandle(vidx), v2f);
|
|
}
|
|
break;
|
|
|
|
case Chunk::Type_Color:
|
|
|
|
assert( OMFormat::dimensions(chunk_header_) == 3 );
|
|
|
|
_opt += Options::VertexColor;
|
|
|
|
for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx)
|
|
{
|
|
bytes_ += vector_restore( _is, v3uc, _swap );
|
|
_bi.set_color( VertexHandle(vidx), v3uc );
|
|
}
|
|
break;
|
|
|
|
case Chunk::Type_Custom:
|
|
|
|
bytes_ +=
|
|
restore_binary_custom_data( _is,
|
|
_bi.kernel()->_get_vprop( property_name_ ),
|
|
header_.n_vertices_,
|
|
_swap );
|
|
|
|
vidx = header_.n_vertices_;
|
|
|
|
break;
|
|
|
|
default: // skip unknown chunks
|
|
{
|
|
omerr() << "Unknown chunk type ignored!\n";
|
|
size_t size_of = header_.n_vertices_
|
|
* OMFormat::vector_size(chunk_header_);
|
|
_is.ignore( size_of );
|
|
bytes_ += size_of;
|
|
}
|
|
}
|
|
|
|
// all chunk data has been read..?!
|
|
return vidx == header_.n_vertices_;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool
|
|
_OMReader_::read_binary_face_chunk( std::istream &_is,
|
|
BaseImporter &_bi,
|
|
Options &_opt,
|
|
bool _swap ) const
|
|
{
|
|
using OMFormat::Chunk;
|
|
|
|
assert( chunk_header_.entity_ == Chunk::Entity_Face );
|
|
|
|
size_t fidx=0;
|
|
OpenMesh::Vec3f v3f; // normal
|
|
OpenMesh::Vec3uc v3uc; // rgb
|
|
|
|
switch( chunk_header_.type_ )
|
|
{
|
|
case Chunk::Type_Topology:
|
|
{
|
|
BaseImporter::VHandles vhandles;
|
|
size_t nV = 0;
|
|
size_t vidx = 0;
|
|
|
|
switch( header_.mesh_ )
|
|
{
|
|
case 'T': nV = 3; break;
|
|
case 'Q': nV = 4; break;
|
|
}
|
|
|
|
for (; fidx < header_.n_faces_; ++fidx)
|
|
{
|
|
if ( header_.mesh_ == 'P' )
|
|
bytes_ += restore( _is, nV, Chunk::Integer_16, _swap );
|
|
|
|
vhandles.clear();
|
|
for (size_t j=0; j<nV; ++j)
|
|
{
|
|
bytes_ += restore( _is, vidx,
|
|
Chunk::Integer_Size(chunk_header_.bits_),
|
|
_swap );
|
|
|
|
vhandles.push_back(VertexHandle(vidx));
|
|
}
|
|
|
|
_bi.add_face(vhandles);
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case Chunk::Type_Normal:
|
|
assert( OMFormat::dimensions(chunk_header_)
|
|
== size_t(OpenMesh::Vec3f::dim()) );
|
|
|
|
_opt += Options::FaceNormal;
|
|
for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx)
|
|
{
|
|
bytes_ += vector_restore( _is, v3f, _swap );
|
|
_bi.set_normal(FaceHandle(fidx), v3f);
|
|
}
|
|
break;
|
|
|
|
|
|
case Chunk::Type_Color:
|
|
|
|
assert( OMFormat::dimensions(chunk_header_) == 3 );
|
|
|
|
_opt += Options::FaceColor;
|
|
for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx)
|
|
{
|
|
bytes_ += vector_restore( _is, v3uc, _swap );
|
|
_bi.set_color( FaceHandle(fidx), v3uc );
|
|
}
|
|
break;
|
|
|
|
|
|
case Chunk::Type_Custom:
|
|
|
|
bytes_ +=
|
|
restore_binary_custom_data( _is,
|
|
_bi.kernel()->_get_fprop( property_name_ ),
|
|
header_.n_faces_,
|
|
_swap );
|
|
|
|
fidx = header_.n_faces_;
|
|
|
|
break;
|
|
|
|
default: // skip unknown chunks
|
|
{
|
|
omerr() << "Unknown chunk type ignore!\n";
|
|
size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_);
|
|
_is.ignore( size_of );
|
|
bytes_ += size_of;
|
|
}
|
|
}
|
|
return fidx == header_.n_faces_;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool
|
|
_OMReader_::read_binary_edge_chunk( std::istream &_is,
|
|
BaseImporter &_bi,
|
|
Options &/*_opt */,
|
|
bool _swap ) const
|
|
{
|
|
using OMFormat::Chunk;
|
|
|
|
assert( chunk_header_.entity_ == Chunk::Entity_Edge );
|
|
|
|
size_t b=bytes_;
|
|
|
|
switch( chunk_header_.type_ )
|
|
{
|
|
case Chunk::Type_Custom:
|
|
|
|
bytes_ +=
|
|
restore_binary_custom_data( _is,
|
|
_bi.kernel()->_get_eprop( property_name_ ),
|
|
header_.n_edges_,
|
|
_swap );
|
|
|
|
break;
|
|
|
|
default:
|
|
// skip unknown type
|
|
size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_);
|
|
_is.ignore( size_of );
|
|
bytes_ += size_of;
|
|
}
|
|
|
|
return b < bytes_;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool
|
|
_OMReader_::read_binary_halfedge_chunk( std::istream &_is,
|
|
BaseImporter &_bi,
|
|
Options &/* _opt */,
|
|
bool _swap ) const
|
|
{
|
|
using OMFormat::Chunk;
|
|
|
|
assert( chunk_header_.entity_ == Chunk::Entity_Halfedge );
|
|
|
|
size_t b = bytes_;
|
|
|
|
switch( chunk_header_.type_ )
|
|
{
|
|
case Chunk::Type_Custom:
|
|
|
|
bytes_ +=
|
|
restore_binary_custom_data( _is,
|
|
_bi.kernel()->_get_hprop( property_name_ ),
|
|
2*header_.n_edges_,
|
|
_swap );
|
|
break;
|
|
|
|
default:
|
|
// skip unknown chunk
|
|
omerr() << "Unknown chunk type ignored!\n";
|
|
size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_);
|
|
_is.ignore( size_of );
|
|
bytes_ += size_of;
|
|
}
|
|
|
|
return b < bytes_;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool
|
|
_OMReader_::read_binary_mesh_chunk( std::istream &_is,
|
|
BaseImporter &_bi,
|
|
Options & /* _opt */,
|
|
bool _swap ) const
|
|
{
|
|
using OMFormat::Chunk;
|
|
|
|
assert( chunk_header_.entity_ == Chunk::Entity_Mesh );
|
|
|
|
size_t b = bytes_;
|
|
|
|
switch( chunk_header_.type_ )
|
|
{
|
|
case Chunk::Type_Custom:
|
|
|
|
bytes_ +=
|
|
restore_binary_custom_data( _is,
|
|
_bi.kernel()->_get_mprop( property_name_ ),
|
|
1,
|
|
_swap );
|
|
|
|
break;
|
|
|
|
default:
|
|
// skip unknown chunk
|
|
size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_);
|
|
_is.ignore( size_of );
|
|
bytes_ += size_of;
|
|
}
|
|
|
|
return b < bytes_;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
size_t
|
|
_OMReader_::restore_binary_custom_data( std::istream& _is, BaseProperty* _bp,
|
|
size_t _n_elem, bool _swap) const
|
|
{
|
|
assert( !_bp || (_bp->name() == property_name_) );
|
|
|
|
using OMFormat::Chunk;
|
|
|
|
size_t bytes = 0;
|
|
Chunk::esize_t block_size;
|
|
Chunk::PropertyName custom_prop;
|
|
|
|
bytes += binary<Chunk::esize_t>::restore( _is, block_size, _swap );
|
|
|
|
|
|
if ( _bp )
|
|
{
|
|
#if defined(OM_DEBUG)
|
|
size_t b;
|
|
#endif
|
|
size_t n_bytes = _bp->size_of( _n_elem );
|
|
|
|
if ( ((n_bytes == BaseProperty::UnknownSize) || (n_bytes == block_size)) &&
|
|
(_bp->element_size() == BaseProperty::UnknownSize ||
|
|
(_n_elem * _bp->element_size() == block_size) ) )
|
|
{
|
|
#if defined(OM_DEBUG)
|
|
bytes += (b=_bp->restore( _is, _swap ));
|
|
#else
|
|
bytes += _bp->restore( _is, _swap );
|
|
#endif
|
|
#if defined(OM_DEBUG)
|
|
assert( block_size == b );
|
|
#endif
|
|
assert( block_size == _bp->size_of() );
|
|
|
|
block_size = 0;
|
|
}
|
|
else
|
|
{
|
|
omerr() << "Warning! Property " << _bp->name() << " not loaded: "
|
|
<< "Mismatching data sizes!n";
|
|
}
|
|
}
|
|
|
|
if (block_size)
|
|
{
|
|
_is.ignore( block_size );
|
|
bytes += block_size;
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//=============================================================================
|
|
} // namespace IO
|
|
} // namespace OpenMesh
|
|
//=============================================================================
|