56#include <OpenMesh/Core/Utils/Endian.hh>
57#include <OpenMesh/Core/IO/OMFormat.hh>
58#include <OpenMesh/Core/IO/reader/OMReader.hh>
59#include <OpenMesh/Core/IO/writer/OMWriter.hh>
60#include <OpenMesh/Core/Utils/typename.hh>
62#include <OpenMesh/Core/Utils/PropertyCreator.hh>
83_OMReader_::_OMReader_()
102 std::ifstream ifs(_filename.c_str(), std::ios::binary);
108 ifs.unsetf(std::ios::skipws);
110 if (!ifs.is_open() || !ifs.good()) {
111 omerr() <<
"[OMReader] : cannot not open file " << _filename << std::endl;
116 bool result =
read(ifs, _bi, _opt);
121 _opt = _opt & fileOptions_;
139 omerr() <<
"[OMReader] : cannot read from stream " << std::endl;
144 bool result = read_binary(_is, _bi, _opt);
149 _opt = _opt & fileOptions_;
167bool _OMReader_::read_binary(std::istream& _is,
BaseImporter& _bi,
const Options& _opt)
const
174 bytes_ += restore(_is, header_, swap_required);
177 if (header_.version_ > _OMWriter_::get_version())
179 omerr() <<
"File uses .om version " << OMFormat::as_string(header_.version_) <<
" but reader only "
180 <<
"supports up to version " << OMFormat::as_string(_OMWriter_::get_version()) <<
".\n"
181 <<
"Please update your OpenMesh." << std::endl;
186 bytes_ += restore(_is, chunk_header_, swap_required);
192 if (chunk_header_.name_) {
193 OMFormat::Chunk::PropertyName pn;
194 bytes_ += restore(_is, property_name_, swap_required);
199 switch (chunk_header_.entity_) {
200 case OMFormat::Chunk::Entity_Vertex:
201 if (!read_binary_vertex_chunk(_is, _bi, _opt, swap_required))
204 case OMFormat::Chunk::Entity_Face:
205 if (!read_binary_face_chunk(_is, _bi, _opt, swap_required))
208 case OMFormat::Chunk::Entity_Edge:
209 if (!read_binary_edge_chunk(_is, _bi, _opt, swap_required))
212 case OMFormat::Chunk::Entity_Halfedge:
213 if (!read_binary_halfedge_chunk(_is, _bi, _opt, swap_required))
216 case OMFormat::Chunk::Entity_Mesh:
217 if (!read_binary_mesh_chunk(_is, _bi, _opt, swap_required))
220 case OMFormat::Chunk::Entity_Sentinel:
240 std::ifstream ifile(_filename.c_str());
251 std::vector<char> evt;
255 while (evt.size() < 4)
256 evt.push_back(
static_cast<char>(_is.get()));
259 std::vector<char>::reverse_iterator it = evt.rbegin();
260 while (it != evt.rend())
264 OMFormat::Header *hdr = (OMFormat::Header*) &evt[0];
267 if (hdr->magic_[0] !=
'O' || hdr->magic_[1] !=
'M')
271 switch (hdr->mesh_) {
281 return supports(hdr->version_);
286bool _OMReader_::supports(
const OMFormat::uint8 )
const
294bool _OMReader_::read_binary_vertex_chunk(std::istream &_is,
BaseImporter &_bi,
const Options &_opt,
bool _swap)
const
296 using OMFormat::Chunk;
298 assert( chunk_header_.entity_ == Chunk::Entity_Vertex);
306 OMFormat::Chunk::PropertyName custom_prop;
309 switch (chunk_header_.type_) {
310 case Chunk::Type_Pos:
311 if (chunk_header_.bits_ == OMFormat::bits(0.0f))
315 for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
316 bytes_ += vector_restore(_is, v3f, _swap);
320 else if (chunk_header_.bits_ == OMFormat::bits(0.0))
324 for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
325 bytes_ += vector_restore(_is, v3d, _swap);
331 omerr() <<
"unknown Vector size" << std::endl;
335 case Chunk::Type_Normal:
337 if (chunk_header_.bits_ == OMFormat::bits(0.0f))
342 for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
343 bytes_ += vector_restore(_is, v3f, _swap);
344 if (fileOptions_.vertex_has_normal() && _opt.vertex_has_normal())
345 _bi.set_normal(VertexHandle(
int(vidx)), v3f);
348 else if (chunk_header_.bits_ == OMFormat::bits(0.0))
353 for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
354 bytes_ += vector_restore(_is, v3d, _swap);
355 if (fileOptions_.vertex_has_normal() && _opt.vertex_has_normal())
356 _bi.set_normal(VertexHandle(
int(vidx)), v3d);
361 omerr() <<
"Unknown vertex normal format" << std::endl;
365 case Chunk::Type_Texcoord:
369 for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
370 bytes_ += vector_restore(_is, v2f, _swap);
371 if (fileOptions_.vertex_has_texcoord() && _opt.vertex_has_texcoord())
372 _bi.set_texcoord(VertexHandle(
int(vidx)), v2f);
376 case Chunk::Type_Color:
378 assert( OMFormat::dimensions(chunk_header_) == 3);
382 for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
383 bytes_ += vector_restore(_is, v3uc, _swap);
384 if (fileOptions_.vertex_has_color() && _opt.vertex_has_color())
385 _bi.set_color(VertexHandle(
int(vidx)), v3uc);
389 case Chunk::Type_Status:
391 assert( OMFormat::dimensions(chunk_header_) == 1);
395 for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
396 bytes_ += restore(_is, status, _swap);
397 if (fileOptions_.vertex_has_status() && _opt.vertex_has_status())
398 _bi.set_status(VertexHandle(
int(vidx)), status);
403 case Chunk::Type_Custom:
405 if(header_.version_ > OMFormat::mk_version(2,1))
407 Chunk::PropertyName property_type;
408 bytes_ += restore(_is, property_type, _swap);
410 add_generic_property(property_type, _bi);
413 bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_vprop(property_name_), header_.n_vertices_, _swap);
414 vidx = header_.n_vertices_;
419 case Chunk::Type_Topology:
421 for (; vidx < header_.n_vertices_; ++vidx)
424 bytes_ += restore( _is, halfedge_id, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap );
426 _bi.set_halfedge(VertexHandle(
static_cast<int>(vidx)), HalfedgeHandle(halfedge_id));
434 omerr() <<
"Unknown chunk type ignored!\n";
435 size_t chunk_size = header_.n_vertices_ * OMFormat::vector_size(chunk_header_);
436 _is.ignore(chunk_size);
437 bytes_ += chunk_size;
444 return vidx == header_.n_vertices_;
450bool _OMReader_::read_binary_face_chunk(std::istream &_is,
BaseImporter &_bi,
const Options &_opt,
bool _swap)
const
452 using OMFormat::Chunk;
454 assert( chunk_header_.entity_ == Chunk::Entity_Face);
462 switch (chunk_header_.type_) {
463 case Chunk::Type_Topology:
465 if (header_.version_ < OMFormat::mk_version(2,0))
468 BaseImporter::VHandles vhandles;
472 switch (header_.mesh_) {
481 for (; fidx < header_.n_faces_; ++fidx) {
482 if (header_.mesh_ ==
'P')
483 bytes_ += restore(_is, nV, Chunk::Integer_16, _swap);
486 for (
size_t j = 0; j < nV; ++j) {
487 bytes_ += restore(_is, vidx, Chunk::Integer_Size(chunk_header_.bits_), _swap);
489 vhandles.push_back(VertexHandle(
int(vidx)));
492 _bi.add_face(vhandles);
498 for (; fidx < header_.n_faces_; ++fidx)
501 bytes_ += restore( _is, halfedge_id, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap );
503 _bi.add_face(HalfedgeHandle(halfedge_id));
509 case Chunk::Type_Normal:
514 if (chunk_header_.bits_ == OMFormat::bits(0.0f))
516 for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) {
517 bytes_ += vector_restore(_is, v3f, _swap);
518 if( fileOptions_.face_has_normal() && _opt.face_has_normal())
519 _bi.set_normal(FaceHandle(
int(fidx)), v3f);
522 else if (chunk_header_.bits_ == OMFormat::bits(0.0))
524 for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) {
525 bytes_ += vector_restore(_is, v3d, _swap);
526 if( fileOptions_.face_has_normal() && _opt.face_has_normal())
527 _bi.set_normal(FaceHandle(
int(fidx)), v3d);
532 omerr() <<
"Unknown face normal format" << std::endl;
536 case Chunk::Type_Color:
538 assert( OMFormat::dimensions(chunk_header_) == 3);
541 for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) {
542 bytes_ += vector_restore(_is, v3uc, _swap);
543 if( fileOptions_.face_has_color() && _opt.face_has_color())
544 _bi.set_color(FaceHandle(
int(fidx)), v3uc);
547 case Chunk::Type_Status:
549 assert( OMFormat::dimensions(chunk_header_) == 1);
553 for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) {
554 bytes_ += restore(_is, status, _swap);
555 if (fileOptions_.face_has_status() && _opt.face_has_status())
556 _bi.set_status(FaceHandle(
int(fidx)), status);
561 case Chunk::Type_Custom:
563 if(header_.version_ > OMFormat::mk_version(2,1))
565 Chunk::PropertyName property_type;
566 bytes_ += restore(_is, property_type, _swap);
568 add_generic_property(property_type, _bi);
571 bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_fprop(property_name_), header_.n_faces_, _swap);
573 fidx = header_.n_faces_;
580 omerr() <<
"Unknown chunk type ignore!\n";
581 size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_);
582 _is.ignore(chunk_size);
583 bytes_ += chunk_size;
586 return fidx == header_.n_faces_;
592bool _OMReader_::read_binary_edge_chunk(std::istream &_is,
BaseImporter &_bi,
const Options &_opt,
bool _swap)
const
594 using OMFormat::Chunk;
596 assert( chunk_header_.entity_ == Chunk::Entity_Edge);
602 switch (chunk_header_.type_) {
603 case Chunk::Type_Custom:
605 if(header_.version_ > OMFormat::mk_version(2,1))
607 Chunk::PropertyName property_type;
608 bytes_ += restore(_is, property_type, _swap);
610 add_generic_property(property_type, _bi);
613 bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_eprop(property_name_), header_.n_edges_, _swap);
617 case Chunk::Type_Status:
619 assert( OMFormat::dimensions(chunk_header_) == 1);
623 for (
size_t eidx = 0; eidx < header_.n_edges_ && !_is.eof(); ++eidx) {
624 bytes_ += restore(_is, status, _swap);
625 if (fileOptions_.edge_has_status() && _opt.edge_has_status())
626 _bi.set_status(EdgeHandle(
int(eidx)), status);
633 size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_);
634 _is.ignore(chunk_size);
635 bytes_ += chunk_size;
644bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is,
BaseImporter &_bi,
const Options & _opt,
bool _swap)
const
646 using OMFormat::Chunk;
648 assert( chunk_header_.entity_ == Chunk::Entity_Halfedge);
653 switch (chunk_header_.type_) {
654 case Chunk::Type_Custom:
656 if(header_.version_ > OMFormat::mk_version(2,1))
658 Chunk::PropertyName property_type;
659 bytes_ += restore(_is, property_type, _swap);
661 add_generic_property(property_type, _bi);
664 bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_hprop(property_name_), 2 * header_.n_edges_, _swap);
669 case Chunk::Type_Texcoord:
675 if (_opt.face_has_texcoord())
677 _bi.request_face_texcoords2D();
680 for (
size_t e_idx = 0; e_idx < header_.n_edges_*2; ++e_idx)
682 bytes_ += vector_restore(_is, v2f, _swap);
683 if (_opt.face_has_texcoord())
684 _bi.set_texcoord(HalfedgeHandle(
int(e_idx)), v2f);
689 case Chunk::Type_Topology:
691 std::vector<HalfedgeHandle> next_halfedges;
692 for (
size_t e_idx = 0; e_idx < header_.n_edges_; ++e_idx)
695 int to_vertex_id_0 = -1;
697 bytes_ += restore( _is, next_id_0, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap );
698 bytes_ += restore( _is, to_vertex_id_0, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap );
699 bytes_ += restore( _is, face_id_0, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap );
702 int to_vertex_id_1 = -1;
704 bytes_ += restore( _is, next_id_1, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap );
705 bytes_ += restore( _is, to_vertex_id_1, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap );
706 bytes_ += restore( _is, face_id_1, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap );
708 auto heh0 = _bi.add_edge(VertexHandle(to_vertex_id_1), VertexHandle(to_vertex_id_0));
709 auto heh1 = HalfedgeHandle(heh0.idx() + 1);
711 next_halfedges.push_back(HalfedgeHandle(next_id_0));
712 next_halfedges.push_back(HalfedgeHandle(next_id_1));
714 _bi.set_face(heh0, FaceHandle(face_id_0));
715 _bi.set_face(heh1, FaceHandle(face_id_1));
718 for (
size_t i = 0; i < next_halfedges.size(); ++i)
719 _bi.set_next(HalfedgeHandle(
static_cast<int>(i)), next_halfedges[i]);
724 case Chunk::Type_Status:
726 assert( OMFormat::dimensions(chunk_header_) == 1);
730 for (
size_t hidx = 0; hidx < header_.n_edges_ * 2 && !_is.eof(); ++hidx) {
731 bytes_ += restore(_is, status, _swap);
732 if (fileOptions_.halfedge_has_status() && _opt.halfedge_has_status())
733 _bi.set_status(HalfedgeHandle(
int(hidx)), status);
740 omerr() <<
"Unknown chunk type ignored!\n";
741 size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_);
742 _is.ignore(chunk_size);
743 bytes_ += chunk_size;
752bool _OMReader_::read_binary_mesh_chunk(std::istream &_is,
BaseImporter &_bi,
const Options& _opt ,
bool _swap)
const
754 using OMFormat::Chunk;
756 assert( chunk_header_.entity_ == Chunk::Entity_Mesh);
760 switch (chunk_header_.type_) {
761 case Chunk::Type_Custom:
763 if(header_.version_ > OMFormat::mk_version(2,1))
765 Chunk::PropertyName property_type;
766 bytes_ += restore(_is, property_type, _swap);
768 add_generic_property(property_type, _bi);
771 bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_mprop(property_name_), 1, _swap);
777 size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_);
778 _is.ignore(chunk_size);
779 bytes_ += chunk_size;
789size_t _OMReader_::restore_binary_custom_data(std::istream& _is, BaseProperty* _bp,
size_t _n_elem,
bool _swap)
const
791 assert( !_bp || (_bp->name() == property_name_));
793 using OMFormat::Chunk;
796 Chunk::esize_t block_size;
797 Chunk::PropertyName custom_prop;
799 bytes += restore(_is, block_size, OMFormat::Chunk::Integer_32, _swap);
802 size_t n_bytes = _bp->size_of(_n_elem);
808 bytes += (b=_bp->restore( _is, _swap ));
810 bytes += _bp->restore(_is, _swap);
814 assert( block_size == b);
817 assert( block_size == _bp->size_of());
821 omerr() <<
"Warning! Property " << _bp->name() <<
" not loaded: " <<
"Mismatching data sizes!" << std::endl;
826 _is.ignore(block_size);
835void _OMReader_:: add_generic_property(OMFormat::Chunk::PropertyName& _property_type,
BaseImporter& _bi)
const
845 PropertyCreationManager& manager = PropertyCreationManager::instance();
846 switch (chunk_header_.entity_)
848 case OMFormat::Chunk::Entity_Vertex:
850 if (_bi.kernel()->_get_vprop(property_name_) ==
nullptr)
854 case OMFormat::Chunk::Entity_Face:
856 if (_bi.kernel()->_get_fprop(property_name_) ==
nullptr)
860 case OMFormat::Chunk::Entity_Edge:
862 if (_bi.kernel()->_get_eprop(property_name_) ==
nullptr)
866 case OMFormat::Chunk::Entity_Halfedge:
868 if (_bi.kernel()->_get_hprop(property_name_) ==
nullptr)
872 case OMFormat::Chunk::Entity_Mesh:
874 if (_bi.kernel()->_get_mprop(property_name_) ==
nullptr)
878 case OMFormat::Chunk::Entity_Sentinel:
static const size_t UnknownSize
Indicates an error when a size is returned by a member.
@ MSB
big endian (Motorola's 68x family, DEC Alpha, MIPS)
static Type local()
Return endian type of host system.
virtual bool can_u_read(const std::string &_filename) const
Returns true if writer can parse _filename (checks extension). _filename can also provide an extensio...
Set options for reader/writer modules.
@ FaceNormal
Has (r) / store (w) face normals.
@ Swap
Swap byte order in binary mode.
@ FaceColor
Has (r) / store (w) face colors.
@ Binary
Set binary mode for r/w.
@ Status
Has (r) / store (w) status properties.
@ VertexNormal
Has (r) / store (w) vertex normals.
@ VertexTexCoord
Has (r) / store (w) texture coordinates.
@ VertexColor
Has (r) / store (w) vertex colors.
@ Custom
Has (r) / store (w) custom properties marked persistent (currently PLY only supports reading and only...
bool register_module(BaseReader *_bl)
virtual bool can_u_read(const std::string &_filename) const override
Returns true if writer can parse _filename (checks extension). _filename can also provide an extensio...
bool read(const std::string &_filename, BaseImporter &_bi, Options &_opt) override
static constexpr int dim()
returns dimension of the vector (deprecated)
_IOManager_ & IOManager()
_OMReader_ __OMReaderInstance
Declare the single entity of the OM reader.
Handle for a edge entity.
Handle for a face entity.
Handle for a halfedge entity.
Handle type for meshes to simplify some template programming.
Handle for a vertex entity.