Developer Documentation
OMReader.cc
1 /* ========================================================================= *
2  * *
3  * OpenMesh *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openmesh.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenMesh. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40  * ========================================================================= */
41 
42 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Date$ *
46  * *
47 \*===========================================================================*/
48 
49 
50 //== INCLUDES =================================================================
51 
52 
53 //STL
54 #include <vector>
55 #include <istream>
56 #include <fstream>
57 
58 // OpenMesh
61 #include <OpenMesh/Core/Utils/Endian.hh>
62 #include <OpenMesh/Core/IO/OMFormat.hh>
63 #include <OpenMesh/Core/IO/reader/OMReader.hh>
64 
65 
66 //=== NAMESPACES ==============================================================
67 
68 
69 namespace OpenMesh {
70 namespace IO {
71 
72 
73 //=== INSTANCIATE =============================================================
74 
75 
76 // register the OMReader singleton with MeshReader
78 _OMReader_& OMReader() { return __OMReaderInstance; }
79 
80 
81 
82 //=== IMPLEMENTATION ==========================================================
83 
84 
85 _OMReader_::_OMReader_()
86 {
87  IOManager().register_module(this);
88 }
89 
90 
91 //-----------------------------------------------------------------------------
92 
93 
94 bool _OMReader_::read(const std::string& _filename, BaseImporter& _bi, Options& _opt)
95 {
96  // check whether importer can give us an OpenMesh BaseKernel
97  if (!_bi.kernel())
98  return false;
99 
100  _opt += Options::Binary; // only binary format supported!
101  fileOptions_ = Options::Binary;
102 
103  // Open file
104  std::ifstream ifs(_filename.c_str(), std::ios::binary);
105 
106  /* Clear formatting flag skipws (Skip whitespaces). If set, operator>> will
107  * skip bytes set to whitespace chars (e.g. 0x20 bytes) in
108  * Property<bool>::restore.
109  */
110  ifs.unsetf(std::ios::skipws);
111 
112  if (!ifs.is_open() || !ifs.good()) {
113  omerr() << "[OMReader] : cannot not open file " << _filename << std::endl;
114  return false;
115  }
116 
117  // Pass stream to read method, remember result
118  bool result = read(ifs, _bi, _opt);
119 
120  // close input stream
121  ifs.close();
122 
123  _opt = _opt & fileOptions_;
124 
125  return result;
126 }
127 
128 //-----------------------------------------------------------------------------
129 
130 
131 bool _OMReader_::read(std::istream& _is, BaseImporter& _bi, Options& _opt)
132 {
133  // check whether importer can give us an OpenMesh BaseKernel
134  if (!_bi.kernel())
135  return false;
136 
137  _opt += Options::Binary; // only binary format supported!
138  fileOptions_ = Options::Binary;
139 
140  if (!_is.good()) {
141  omerr() << "[OMReader] : cannot read from stream " << std::endl;
142  return false;
143  }
144 
145  // Pass stream to read method, remember result
146  bool result = read_binary(_is, _bi, _opt);
147 
148  if (result)
149  _opt += Options::Binary;
150 
151  _opt = _opt & fileOptions_;
152 
153  return result;
154 }
155 
156 
157 
158 //-----------------------------------------------------------------------------
159 
160 bool _OMReader_::read_ascii(std::istream& /* _is */, BaseImporter& /* _bi */, Options& /* _opt */) const
161 {
162  // not supported yet!
163  return false;
164 }
165 
166 
167 //-----------------------------------------------------------------------------
168 
169 bool _OMReader_::read_binary(std::istream& _is, BaseImporter& _bi, Options& _opt) const
170 {
171  bool swap = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB);
172 
173  // Initialize byte counter
174  bytes_ = 0;
175 
176  bytes_ += restore(_is, header_, swap);
177 
178 
179  while (!_is.eof()) {
180  bytes_ += restore(_is, chunk_header_, swap);
181 
182  if (_is.eof())
183  break;
184 
185  // Is this a named property restore the name
186  if (chunk_header_.name_) {
187  OMFormat::Chunk::PropertyName pn;
188  bytes_ += restore(_is, property_name_, swap);
189  }
190 
191  // Read in the property data. If it is an anonymous or unknown named
192  // property, then skip data.
193  switch (chunk_header_.entity_) {
194  case OMFormat::Chunk::Entity_Vertex:
195  if (!read_binary_vertex_chunk(_is, _bi, _opt, swap))
196  return false;
197  break;
198  case OMFormat::Chunk::Entity_Face:
199  if (!read_binary_face_chunk(_is, _bi, _opt, swap))
200  return false;
201  break;
202  case OMFormat::Chunk::Entity_Edge:
203  if (!read_binary_edge_chunk(_is, _bi, _opt, swap))
204  return false;
205  break;
206  case OMFormat::Chunk::Entity_Halfedge:
207  if (!read_binary_halfedge_chunk(_is, _bi, _opt, swap))
208  return false;
209  break;
210  case OMFormat::Chunk::Entity_Mesh:
211  if (!read_binary_mesh_chunk(_is, _bi, _opt, swap))
212  return false;
213  break;
214  default:
215  return false;
216  }
217 
218  }
219 
220  // File was successfully parsed.
221  return true;
222 }
223 
224 
225 //-----------------------------------------------------------------------------
226 
227 bool _OMReader_::can_u_read(const std::string& _filename) const
228 {
229  // !!! Assuming BaseReader::can_u_parse( std::string& )
230  // does not call BaseReader::read_magic()!!!
231  if (this->BaseReader::can_u_read(_filename)) {
232  std::ifstream ifile(_filename.c_str());
233  if (ifile && can_u_read(ifile))
234  return true;
235  }
236  return false;
237 }
238 
239 //-----------------------------------------------------------------------------
240 
241 bool _OMReader_::can_u_read(std::istream& _is) const
242 {
243  std::vector<char> evt;
244  evt.reserve(20);
245 
246  // read first 4 characters into a buffer
247  while (evt.size() < 4)
248  evt.push_back(static_cast<char>(_is.get()));
249 
250  // put back all read characters
251  std::vector<char>::reverse_iterator it = evt.rbegin();
252  while (it != evt.rend())
253  _is.putback(*it++);
254 
255  // evaluate header information
256  OMFormat::Header *hdr = (OMFormat::Header*) &evt[0];
257 
258  // first two characters must be 'OM'
259  if (hdr->magic_[0] != 'O' || hdr->magic_[1] != 'M')
260  return false;
261 
262  // 3rd characters defines the mesh type:
263  switch (hdr->mesh_) {
264  case 'T': // Triangle Mesh
265  case 'Q': // Quad Mesh
266  case 'P': // Polygonal Mesh
267  break;
268  default: // ?
269  return false;
270  }
271 
272  // 4th characters encodes the version
273  return supports(hdr->version_);
274 }
275 
276 //-----------------------------------------------------------------------------
277 
278 bool _OMReader_::supports(const OMFormat::uint8 /* version */) const
279 {
280  return true;
281 }
282 
283 
284 //-----------------------------------------------------------------------------
285 
286 bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi, Options &_opt, bool _swap) const
287 {
288  using OMFormat::Chunk;
289 
290  assert( chunk_header_.entity_ == Chunk::Entity_Vertex);
291 
292  OpenMesh::Vec3f v3f;
293  OpenMesh::Vec2f v2f;
294  OpenMesh::Vec3uc v3uc; // rgb
295 
296  OMFormat::Chunk::PropertyName custom_prop;
297 
298  size_t vidx = 0;
299  switch (chunk_header_.type_) {
300  case Chunk::Type_Pos:
301  assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim()));
302 
303  for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
304  bytes_ += vector_restore(_is, v3f, _swap);
305  _bi.add_vertex(v3f);
306  }
307  break;
308 
309  case Chunk::Type_Normal:
310  assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim()));
311 
312  fileOptions_ += Options::VertexNormal;
313  for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
314  bytes_ += vector_restore(_is, v3f, _swap);
315  if (fileOptions_.vertex_has_normal() && _opt.vertex_has_normal())
316  _bi.set_normal(VertexHandle(int(vidx)), v3f);
317  }
318  break;
319 
320  case Chunk::Type_Texcoord:
321  assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec2f::dim()));
322 
323  fileOptions_ += Options::VertexTexCoord;
324  for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
325  bytes_ += vector_restore(_is, v2f, _swap);
326  if (fileOptions_.vertex_has_texcoord() && _opt.vertex_has_texcoord())
327  _bi.set_texcoord(VertexHandle(int(vidx)), v2f);
328  }
329  break;
330 
331  case Chunk::Type_Color:
332 
333  assert( OMFormat::dimensions(chunk_header_) == 3);
334 
335  fileOptions_ += Options::VertexColor;
336 
337  for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
338  bytes_ += vector_restore(_is, v3uc, _swap);
339  if (fileOptions_.vertex_has_color() && _opt.vertex_has_color())
340  _bi.set_color(VertexHandle(int(vidx)), v3uc);
341  }
342  break;
343 
344  case Chunk::Type_Custom:
345 
346  bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_vprop(property_name_), header_.n_vertices_, _swap);
347 
348  vidx = header_.n_vertices_;
349 
350  break;
351 
352  default: // skip unknown chunks
353  {
354  omerr() << "Unknown chunk type ignored!\n";
355  size_t size_of = header_.n_vertices_ * OMFormat::vector_size(chunk_header_);
356  _is.ignore(size_of);
357  bytes_ += size_of;
358  }
359  }
360 
361  // all chunk data has been read..?!
362  return vidx == header_.n_vertices_;
363 }
364 
365 
366 //-----------------------------------------------------------------------------
367 
368 bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Options &_opt, bool _swap) const
369 {
370  using OMFormat::Chunk;
371 
372  assert( chunk_header_.entity_ == Chunk::Entity_Face);
373 
374  size_t fidx = 0;
375  OpenMesh::Vec3f v3f; // normal
376  OpenMesh::Vec3uc v3uc; // rgb
377 
378  switch (chunk_header_.type_) {
379  case Chunk::Type_Topology: {
380  BaseImporter::VHandles vhandles;
381  size_t nV = 0;
382  size_t vidx = 0;
383 
384  switch (header_.mesh_) {
385  case 'T':
386  nV = 3;
387  break;
388  case 'Q':
389  nV = 4;
390  break;
391  }
392 
393  for (; fidx < header_.n_faces_; ++fidx) {
394  if (header_.mesh_ == 'P')
395  bytes_ += restore(_is, nV, Chunk::Integer_16, _swap);
396 
397  vhandles.clear();
398  for (size_t j = 0; j < nV; ++j) {
399  bytes_ += restore(_is, vidx, Chunk::Integer_Size(chunk_header_.bits_), _swap);
400 
401  vhandles.push_back(VertexHandle(int(vidx)));
402  }
403 
404  _bi.add_face(vhandles);
405  }
406  }
407  break;
408 
409  case Chunk::Type_Normal:
410  assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim()));
411 
412  fileOptions_ += Options::FaceNormal;
413  for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) {
414  bytes_ += vector_restore(_is, v3f, _swap);
415  if( fileOptions_.face_has_normal() && _opt.face_has_normal())
416  _bi.set_normal(FaceHandle(int(fidx)), v3f);
417  }
418  break;
419 
420  case Chunk::Type_Color:
421 
422  assert( OMFormat::dimensions(chunk_header_) == 3);
423 
424  fileOptions_ += Options::FaceColor;
425  for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) {
426  bytes_ += vector_restore(_is, v3uc, _swap);
427  if( fileOptions_.face_has_color() && _opt.face_has_color())
428  _bi.set_color(FaceHandle(int(fidx)), v3uc);
429  }
430  break;
431 
432  case Chunk::Type_Custom:
433 
434  bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_fprop(property_name_), header_.n_faces_, _swap);
435 
436  fidx = header_.n_faces_;
437 
438  break;
439 
440  default: // skip unknown chunks
441  {
442  omerr() << "Unknown chunk type ignore!\n";
443  size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_);
444  _is.ignore(size_of);
445  bytes_ += size_of;
446  }
447  }
448  return fidx == header_.n_faces_;
449 }
450 
451 
452 //-----------------------------------------------------------------------------
453 
454 bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Options &/*_opt */, bool _swap) const
455 {
456  using OMFormat::Chunk;
457 
458  assert( chunk_header_.entity_ == Chunk::Entity_Edge);
459 
460  size_t b = bytes_;
461 
462  switch (chunk_header_.type_) {
463  case Chunk::Type_Custom:
464 
465  bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_eprop(property_name_), header_.n_edges_, _swap);
466 
467  break;
468 
469  default:
470  // skip unknown type
471  size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_);
472  _is.ignore(size_of);
473  bytes_ += size_of;
474  }
475 
476  return b < bytes_;
477 }
478 
479 
480 //-----------------------------------------------------------------------------
481 
482 bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi, Options &/* _opt */, bool _swap) const
483 {
484  using OMFormat::Chunk;
485 
486  assert( chunk_header_.entity_ == Chunk::Entity_Halfedge);
487 
488  size_t b = bytes_;
489 
490  switch (chunk_header_.type_) {
491  case Chunk::Type_Custom:
492 
493  bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_hprop(property_name_), 2 * header_.n_edges_, _swap);
494  break;
495 
496  default:
497  // skip unknown chunk
498  omerr() << "Unknown chunk type ignored!\n";
499  size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_);
500  _is.ignore(size_of);
501  bytes_ += size_of;
502  }
503 
504  return b < bytes_;
505 }
506 
507 
508 //-----------------------------------------------------------------------------
509 
510 bool _OMReader_::read_binary_mesh_chunk(std::istream &_is, BaseImporter &_bi, Options & /* _opt */, bool _swap) const
511 {
512  using OMFormat::Chunk;
513 
514  assert( chunk_header_.entity_ == Chunk::Entity_Mesh);
515 
516  size_t b = bytes_;
517 
518  switch (chunk_header_.type_) {
519  case Chunk::Type_Custom:
520 
521  bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_mprop(property_name_), 1, _swap);
522 
523  break;
524 
525  default:
526  // skip unknown chunk
527  size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_);
528  _is.ignore(size_of);
529  bytes_ += size_of;
530  }
531 
532  return b < bytes_;
533 }
534 
535 
536 //-----------------------------------------------------------------------------
537 
538 
539 size_t _OMReader_::restore_binary_custom_data(std::istream& _is, BaseProperty* _bp, size_t _n_elem, bool _swap) const
540 {
541  assert( !_bp || (_bp->name() == property_name_));
542 
543  using OMFormat::Chunk;
544 
545  size_t bytes = 0;
546  Chunk::esize_t block_size;
547  Chunk::PropertyName custom_prop;
548 
549  bytes += restore(_is, block_size, OMFormat::Chunk::Integer_32, _swap);
550 
551  if (_bp) {
552  size_t n_bytes = _bp->size_of(_n_elem);
553 
554  if (((n_bytes == BaseProperty::UnknownSize) || (n_bytes == block_size))
555  && (_bp->element_size() == BaseProperty::UnknownSize || (_n_elem * _bp->element_size() == block_size))) {
556 #if defined(OM_DEBUG)
557  size_t b;
558  bytes += (b=_bp->restore( _is, _swap ));
559 #else
560  bytes += _bp->restore(_is, _swap);
561 #endif
562 
563 #if defined(OM_DEBUG)
564  assert( block_size == b );
565 #endif
566 
567  assert( block_size == _bp->size_of());
568 
569  block_size = 0;
570  } else {
571  omerr() << "Warning! Property " << _bp->name() << " not loaded: " << "Mismatching data sizes!n";
572  }
573  }
574 
575  if (block_size) {
576  _is.ignore(block_size);
577  bytes += block_size;
578  }
579 
580  return bytes;
581 }
582 
583 
584 //-----------------------------------------------------------------------------
585 
586 //=============================================================================
587 } // namespace IO
588 } // namespace OpenMesh
589 //=============================================================================
_OMReader_ __OMReaderInstance
Declare the single entity of the OM reader.
Definition: OMReader.cc:77
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...
Definition: BaseReader.cc:82
Has (r) / store (w) texture coordinates.
Definition: Options.hh:111
big endian (Motorola&#39;s 68x family, DEC Alpha, MIPS)
Definition: Endian.hh:84
Set binary mode for r/w.
Definition: Options.hh:105
Has (r) / store (w) vertex normals.
Definition: Options.hh:109
Has (r) / store (w) face normals.
Definition: Options.hh:113
virtual size_t size_of() const
Return size of property in bytes.
static constexpr int dim()
returns dimension of the vector (deprecated)
Definition: Vector11T.hh:102
virtual size_t restore(std::istream &_istr, bool _swap)=0
size_t size_of(const T &_v)
Definition: StoreRestore.hh:94
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...
Definition: OMReader.cc:227
static const size_t UnknownSize
Indicates an error when a size is returned by a member.
Definition: BaseProperty.hh:70
virtual size_t element_size() const =0
Size of one element in bytes or UnknownSize if not known.
Set options for reader/writer modules.
Definition: Options.hh:95
Handle for a vertex entity.
Definition: Handles.hh:125
const std::string & name() const
Return the name of the property.
bool read(const std::string &_filename, BaseImporter &_bi, Options &_opt)
Definition: OMReader.cc:94
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:222
Swap byte order in binary mode.
Definition: Options.hh:108
Handle for a face entity.
Definition: Handles.hh:146
Has (r) / store (w) face colors.
Definition: Options.hh:114
Has (r) / store (w) vertex colors.
Definition: Options.hh:110
static Type local()
Return endian type of host system.
Definition: Endian.hh:88
_IOManager_ & IOManager()
Definition: IOManager.cc:77