Developer Documentation
Loading...
Searching...
No Matches
OMReader.cc
1/* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2025, 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
45//== INCLUDES =================================================================
46
47
48//STL
49#include <vector>
50#include <istream>
51#include <fstream>
52
53// OpenMesh
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>
61
62#include <OpenMesh/Core/Utils/PropertyCreator.hh>
63
64//=== NAMESPACES ==============================================================
65
66
67namespace OpenMesh {
68namespace IO {
69
70
71//=== INSTANCIATE =============================================================
72
73
74// register the OMReader singleton with MeshReader
76_OMReader_& OMReader() { return __OMReaderInstance; }
77
78
79
80//=== IMPLEMENTATION ==========================================================
81
82
83_OMReader_::_OMReader_()
84{
86}
87
88
89//-----------------------------------------------------------------------------
90
91
92bool _OMReader_::read(const std::string& _filename, BaseImporter& _bi, Options& _opt)
93{
94 // check whether importer can give us an OpenMesh BaseKernel
95 if (!_bi.kernel())
96 return false;
97
98 _opt += Options::Binary; // only binary format supported!
99 fileOptions_ = Options::Binary;
100
101 // Open file
102 std::ifstream ifs(_filename.c_str(), std::ios::binary);
103
104 /* Clear formatting flag skipws (Skip whitespaces). If set, operator>> will
105 * skip bytes set to whitespace chars (e.g. 0x20 bytes) in
106 * Property<bool>::restore.
107 */
108 ifs.unsetf(std::ios::skipws);
109
110 if (!ifs.is_open() || !ifs.good()) {
111 omerr() << "[OMReader] : cannot not open file " << _filename << std::endl;
112 return false;
113 }
114
115 // Pass stream to read method, remember result
116 bool result = read(ifs, _bi, _opt);
117
118 // close input stream
119 ifs.close();
120
121 _opt = _opt & fileOptions_;
122
123 return result;
124}
125
126//-----------------------------------------------------------------------------
127
128
129bool _OMReader_::read(std::istream& _is, BaseImporter& _bi, Options& _opt)
130{
131 // check whether importer can give us an OpenMesh BaseKernel
132 if (!_bi.kernel())
133 return false;
134
135 _opt += Options::Binary; // only binary format supported!
136 fileOptions_ = Options::Binary;
137
138 if (!_is.good()) {
139 omerr() << "[OMReader] : cannot read from stream " << std::endl;
140 return false;
141 }
142
143 // Pass stream to read method, remember result
144 bool result = read_binary(_is, _bi, _opt);
145
146 if (result)
147 _opt += Options::Binary;
148
149 _opt = _opt & fileOptions_;
150
151 return result;
152}
153
154
155
156//-----------------------------------------------------------------------------
157
158bool _OMReader_::read_ascii(std::istream& /* _is */, BaseImporter& /* _bi */, const Options& /* _opt */) const
159{
160 // not supported yet!
161 return false;
162}
163
164
165//-----------------------------------------------------------------------------
166
167bool _OMReader_::read_binary(std::istream& _is, BaseImporter& _bi, const Options& _opt) const
168{
169 bool swap_required = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB);
170
171 // Initialize byte counter
172 bytes_ = 0;
173
174 bytes_ += restore(_is, header_, swap_required);
175
176
177 if (header_.version_ > _OMWriter_::get_version())
178 {
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;
182 return false;
183 }
184
185 while (!_is.eof()) {
186 bytes_ += restore(_is, chunk_header_, swap_required);
187
188 if (_is.eof())
189 break;
190
191 // Is this a named property restore the name
192 if (chunk_header_.name_) {
193 OMFormat::Chunk::PropertyName pn;
194 bytes_ += restore(_is, property_name_, swap_required);
195 }
196
197 // Read in the property data. If it is an anonymous or unknown named
198 // property, then skip data.
199 switch (chunk_header_.entity_) {
200 case OMFormat::Chunk::Entity_Vertex:
201 if (!read_binary_vertex_chunk(_is, _bi, _opt, swap_required))
202 return false;
203 break;
204 case OMFormat::Chunk::Entity_Face:
205 if (!read_binary_face_chunk(_is, _bi, _opt, swap_required))
206 return false;
207 break;
208 case OMFormat::Chunk::Entity_Edge:
209 if (!read_binary_edge_chunk(_is, _bi, _opt, swap_required))
210 return false;
211 break;
212 case OMFormat::Chunk::Entity_Halfedge:
213 if (!read_binary_halfedge_chunk(_is, _bi, _opt, swap_required))
214 return false;
215 break;
216 case OMFormat::Chunk::Entity_Mesh:
217 if (!read_binary_mesh_chunk(_is, _bi, _opt, swap_required))
218 return false;
219 break;
220 case OMFormat::Chunk::Entity_Sentinel:
221 return true;
222 default:
223 return false;
224 }
225
226 }
227
228 // File was successfully parsed.
229 return true;
230}
231
232
233//-----------------------------------------------------------------------------
234
235bool _OMReader_::can_u_read(const std::string& _filename) const
236{
237 // !!! Assuming BaseReader::can_u_parse( std::string& )
238 // does not call BaseReader::read_magic()!!!
239 if (this->BaseReader::can_u_read(_filename)) {
240 std::ifstream ifile(_filename.c_str());
241 if (ifile && can_u_read(ifile))
242 return true;
243 }
244 return false;
245}
246
247//-----------------------------------------------------------------------------
248
249bool _OMReader_::can_u_read(std::istream& _is) const
250{
251 std::vector<char> evt;
252 evt.reserve(20);
253
254 // read first 4 characters into a buffer
255 while (evt.size() < 4)
256 evt.push_back(static_cast<char>(_is.get()));
257
258 // put back all read characters
259 std::vector<char>::reverse_iterator it = evt.rbegin();
260 while (it != evt.rend())
261 _is.putback(*it++);
262
263 // evaluate header information
264 OMFormat::Header *hdr = (OMFormat::Header*) &evt[0];
265
266 // first two characters must be 'OM'
267 if (hdr->magic_[0] != 'O' || hdr->magic_[1] != 'M')
268 return false;
269
270 // 3rd characters defines the mesh type:
271 switch (hdr->mesh_) {
272 case 'T': // Triangle Mesh
273 case 'Q': // Quad Mesh
274 case 'P': // Polygonal Mesh
275 break;
276 default: // ?
277 return false;
278 }
279
280 // 4th characters encodes the version
281 return supports(hdr->version_);
282}
283
284//-----------------------------------------------------------------------------
285
286bool _OMReader_::supports(const OMFormat::uint8 /* version */) const
287{
288 return true;
289}
290
291
292//-----------------------------------------------------------------------------
293
294bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi, const Options &_opt, bool _swap) const
295{
296 using OMFormat::Chunk;
297
298 assert( chunk_header_.entity_ == Chunk::Entity_Vertex);
299
300 OpenMesh::Vec3f v3f;
301 OpenMesh::Vec3d v3d;
302 OpenMesh::Vec2f v2f;
303 OpenMesh::Vec3uc v3uc; // rgb
305
306 OMFormat::Chunk::PropertyName custom_prop;
307
308 size_t vidx = 0;
309 switch (chunk_header_.type_) {
310 case Chunk::Type_Pos:
311 if (chunk_header_.bits_ == OMFormat::bits(0.0f)) // read floats
312 {
313 assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim()));
314
315 for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
316 bytes_ += vector_restore(_is, v3f, _swap);
317 _bi.add_vertex(v3f);
318 }
319 }
320 else if (chunk_header_.bits_ == OMFormat::bits(0.0)) // read doubles
321 {
322 assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3d::dim()));
323
324 for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) {
325 bytes_ += vector_restore(_is, v3d, _swap);
326 _bi.add_vertex(v3d);
327 }
328 }
329 else
330 {
331 omerr() << "unknown Vector size" << std::endl;
332 }
333 break;
334
335 case Chunk::Type_Normal:
336
337 if (chunk_header_.bits_ == OMFormat::bits(0.0f)) // read floats
338 {
339 assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim()));
340
341 fileOptions_ += Options::VertexNormal;
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);
346 }
347 }
348 else if (chunk_header_.bits_ == OMFormat::bits(0.0)) // read doubles
349 {
350 assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3d::dim()));
351
352 fileOptions_ += Options::VertexNormal;
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);
357 }
358 }
359 else
360 {
361 omerr() << "Unknown vertex normal format" << std::endl;
362 }
363 break;
364
365 case Chunk::Type_Texcoord:
366 assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec2f::dim()));
367
368 fileOptions_ += Options::VertexTexCoord;
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);
373 }
374 break;
375
376 case Chunk::Type_Color:
377
378 assert( OMFormat::dimensions(chunk_header_) == 3);
379
380 fileOptions_ += Options::VertexColor;
381
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);
386 }
387 break;
388
389 case Chunk::Type_Status:
390 {
391 assert( OMFormat::dimensions(chunk_header_) == 1);
392
393 fileOptions_ += Options::Status;
394
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);
399 }
400 break;
401 }
402
403 case Chunk::Type_Custom:
404 {
405 if(header_.version_ > OMFormat::mk_version(2,1))
406 {
407 Chunk::PropertyName property_type;
408 bytes_ += restore(_is, property_type, _swap);
409 if (_opt.check(Options::Custom))
410 add_generic_property(property_type, _bi);
411 }
412
413 bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_vprop(property_name_), header_.n_vertices_, _swap);
414 vidx = header_.n_vertices_;
415 }
416
417 break;
418
419 case Chunk::Type_Topology:
420 {
421 for (; vidx < header_.n_vertices_; ++vidx)
422 {
423 int halfedge_id = 0;
424 bytes_ += restore( _is, halfedge_id, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap );
425
426 _bi.set_halfedge(VertexHandle(static_cast<int>(vidx)), HalfedgeHandle(halfedge_id));
427 }
428 }
429
430 break;
431
432 default: // skip unknown chunks
433 {
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;
438 break;
439 }
440
441 }
442
443 // all chunk data has been read..?!
444 return vidx == header_.n_vertices_;
445}
446
447
448//-----------------------------------------------------------------------------
449
450bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, const Options &_opt, bool _swap) const
451{
452 using OMFormat::Chunk;
453
454 assert( chunk_header_.entity_ == Chunk::Entity_Face);
455
456 size_t fidx = 0;
457 OpenMesh::Vec3f v3f; // normal
458 OpenMesh::Vec3d v3d; // normal as double
459 OpenMesh::Vec3uc v3uc; // rgb
461
462 switch (chunk_header_.type_) {
463 case Chunk::Type_Topology:
464 {
465 if (header_.version_ < OMFormat::mk_version(2,0))
466 {
467 // add faces based on vertex indices
468 BaseImporter::VHandles vhandles;
469 size_t nV = 0;
470 size_t vidx = 0;
471
472 switch (header_.mesh_) {
473 case 'T':
474 nV = 3;
475 break;
476 case 'Q':
477 nV = 4;
478 break;
479 }
480
481 for (; fidx < header_.n_faces_; ++fidx) {
482 if (header_.mesh_ == 'P')
483 bytes_ += restore(_is, nV, Chunk::Integer_16, _swap);
484
485 vhandles.clear();
486 for (size_t j = 0; j < nV; ++j) {
487 bytes_ += restore(_is, vidx, Chunk::Integer_Size(chunk_header_.bits_), _swap);
488
489 vhandles.push_back(VertexHandle(int(vidx)));
490 }
491
492 _bi.add_face(vhandles);
493 }
494 }
495 else
496 {
497 // add faces by simply setting an incident halfedge
498 for (; fidx < header_.n_faces_; ++fidx)
499 {
500 int halfedge_id = 0;
501 bytes_ += restore( _is, halfedge_id, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap );
502
503 _bi.add_face(HalfedgeHandle(halfedge_id));
504 }
505 }
506 }
507 break;
508
509 case Chunk::Type_Normal:
510 assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim()));
511
512 fileOptions_ += Options::FaceNormal;
513
514 if (chunk_header_.bits_ == OMFormat::bits(0.0f)) // read floats
515 {
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);
520 }
521 }
522 else if (chunk_header_.bits_ == OMFormat::bits(0.0)) // read doubles
523 {
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);
528 }
529 }
530 else
531 {
532 omerr() << "Unknown face normal format" << std::endl;
533 }
534 break;
535
536 case Chunk::Type_Color:
537
538 assert( OMFormat::dimensions(chunk_header_) == 3);
539
540 fileOptions_ += Options::FaceColor;
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);
545 }
546 break;
547 case Chunk::Type_Status:
548 {
549 assert( OMFormat::dimensions(chunk_header_) == 1);
550
551 fileOptions_ += Options::Status;
552
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);
557 }
558 break;
559 }
560
561 case Chunk::Type_Custom:
562 {
563 if(header_.version_ > OMFormat::mk_version(2,1))
564 {
565 Chunk::PropertyName property_type;
566 bytes_ += restore(_is, property_type, _swap);
567 if (_opt.check(Options::Custom))
568 add_generic_property(property_type, _bi);
569 }
570
571 bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_fprop(property_name_), header_.n_faces_, _swap);
572
573 fidx = header_.n_faces_;
574
575 break;
576 }
577
578 default: // skip unknown chunks
579 {
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;
584 }
585 }
586 return fidx == header_.n_faces_;
587}
588
589
590//-----------------------------------------------------------------------------
591
592bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, const Options &_opt, bool _swap) const
593{
594 using OMFormat::Chunk;
595
596 assert( chunk_header_.entity_ == Chunk::Entity_Edge);
597
598 size_t b = bytes_;
599
601
602 switch (chunk_header_.type_) {
603 case Chunk::Type_Custom:
604 {
605 if(header_.version_ > OMFormat::mk_version(2,1))
606 {
607 Chunk::PropertyName property_type;
608 bytes_ += restore(_is, property_type, _swap);
609 if (_opt.check(Options::Custom))
610 add_generic_property(property_type, _bi);
611 }
612
613 bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_eprop(property_name_), header_.n_edges_, _swap);
614
615 break;
616 }
617 case Chunk::Type_Status:
618 {
619 assert( OMFormat::dimensions(chunk_header_) == 1);
620
621 fileOptions_ += Options::Status;
622
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);
627 }
628 break;
629 }
630
631 default:
632 // skip unknown type
633 size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_);
634 _is.ignore(chunk_size);
635 bytes_ += chunk_size;
636 }
637
638 return b < bytes_;
639}
640
641
642//-----------------------------------------------------------------------------
643
644bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi, const Options & _opt, bool _swap) const
645{
646 using OMFormat::Chunk;
647
648 assert( chunk_header_.entity_ == Chunk::Entity_Halfedge);
649
650 size_t b = bytes_;
652
653 switch (chunk_header_.type_) {
654 case Chunk::Type_Custom:
655 {
656 if(header_.version_ > OMFormat::mk_version(2,1))
657 {
658 Chunk::PropertyName property_type;
659 bytes_ += restore(_is, property_type, _swap);
660 if (_opt.check(Options::Custom))
661 add_generic_property(property_type, _bi);
662 }
663
664 bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_hprop(property_name_), 2 * header_.n_edges_, _swap);
665 break;
666 }
667
668 //----------------------------------------------------------------------------------------
669 case Chunk::Type_Texcoord:
670 {
671 assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec2f::dim()));
672
673 //fileOptions_ += OpenMesh::IO::Options::FaceTexCoord;
674
675 if (_opt.face_has_texcoord())
676 {
677 _bi.request_face_texcoords2D();
678 }
679 OpenMesh::Vec2f v2f;
680 for (size_t e_idx = 0; e_idx < header_.n_edges_*2; ++e_idx)
681 {
682 bytes_ += vector_restore(_is, v2f, _swap);
683 if (_opt.face_has_texcoord())
684 _bi.set_texcoord(HalfedgeHandle(int(e_idx)), v2f);
685 }
686 break;
687 }
688 //----------------------------------------------------------------------------------------
689 case Chunk::Type_Topology:
690 {
691 std::vector<HalfedgeHandle> next_halfedges;
692 for (size_t e_idx = 0; e_idx < header_.n_edges_; ++e_idx)
693 {
694 int next_id_0 = -1;
695 int to_vertex_id_0 = -1;
696 int face_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 );
700
701 int next_id_1 = -1;
702 int to_vertex_id_1 = -1;
703 int face_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 );
707
708 auto heh0 = _bi.add_edge(VertexHandle(to_vertex_id_1), VertexHandle(to_vertex_id_0));
709 auto heh1 = HalfedgeHandle(heh0.idx() + 1);
710
711 next_halfedges.push_back(HalfedgeHandle(next_id_0));
712 next_halfedges.push_back(HalfedgeHandle(next_id_1));
713
714 _bi.set_face(heh0, FaceHandle(face_id_0));
715 _bi.set_face(heh1, FaceHandle(face_id_1));
716 }
717
718 for (size_t i = 0; i < next_halfedges.size(); ++i)
719 _bi.set_next(HalfedgeHandle(static_cast<int>(i)), next_halfedges[i]);
720 }
721
722 break;
723
724 case Chunk::Type_Status:
725 {
726 assert( OMFormat::dimensions(chunk_header_) == 1);
727
728 fileOptions_ += Options::Status;
729
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);
734 }
735 break;
736 }
737
738 default:
739 // skip unknown chunk
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;
744 }
745
746 return b < bytes_;
747}
748
749
750//-----------------------------------------------------------------------------
751
752bool _OMReader_::read_binary_mesh_chunk(std::istream &_is, BaseImporter &_bi, const Options& _opt , bool _swap) const
753{
754 using OMFormat::Chunk;
755
756 assert( chunk_header_.entity_ == Chunk::Entity_Mesh);
757
758 size_t b = bytes_;
759
760 switch (chunk_header_.type_) {
761 case Chunk::Type_Custom:
762 {
763 if(header_.version_ > OMFormat::mk_version(2,1))
764 {
765 Chunk::PropertyName property_type;
766 bytes_ += restore(_is, property_type, _swap);
767 if (_opt.check(Options::Custom))
768 add_generic_property(property_type, _bi);
769 }
770
771 bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_mprop(property_name_), 1, _swap);
772
773 break;
774 }
775 default:
776 // skip unknown chunk
777 size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_);
778 _is.ignore(chunk_size);
779 bytes_ += chunk_size;
780 }
781
782 return b < bytes_;
783}
784
785
786//-----------------------------------------------------------------------------
787
788
789size_t _OMReader_::restore_binary_custom_data(std::istream& _is, BaseProperty* _bp, size_t _n_elem, bool _swap) const
790{
791 assert( !_bp || (_bp->name() == property_name_));
792
793 using OMFormat::Chunk;
794
795 size_t bytes = 0;
796 Chunk::esize_t block_size;
797 Chunk::PropertyName custom_prop;
798
799 bytes += restore(_is, block_size, OMFormat::Chunk::Integer_32, _swap);
800
801 if (_bp) {
802 size_t n_bytes = _bp->size_of(_n_elem);
803
804 if (((n_bytes == BaseProperty::UnknownSize) || (n_bytes == block_size))
805 && (_bp->element_size() == BaseProperty::UnknownSize || (_n_elem * _bp->element_size() == block_size))) {
806#if defined(OM_DEBUG)
807 size_t b;
808 bytes += (b=_bp->restore( _is, _swap ));
809#else
810 bytes += _bp->restore(_is, _swap);
811#endif
812
813#if defined(OM_DEBUG)
814 assert( block_size == b);
815#endif
816
817 assert( block_size == _bp->size_of());
818
819 block_size = 0;
820 } else {
821 omerr() << "Warning! Property " << _bp->name() << " not loaded: " << "Mismatching data sizes!" << std::endl;
822 }
823 }
824
825 if (block_size) {
826 _is.ignore(block_size);
827 bytes += block_size;
828 }
829
830 return bytes;
831}
832
833
834//--------------------------------helper
835void _OMReader_:: add_generic_property(OMFormat::Chunk::PropertyName& _property_type, BaseImporter& _bi) const
836{
837 // We want to support the old way of restoring properties, ie.
838 // the user has manually created the corresponding property.
839 // In that case the property does not need be registered.
840 // However, the _bi.kerne()->_get_prop(property_name_) checks below
841 // May return a property with the correct name but the wrong type.
842 // For now we will have to live with that.
843
844
845 PropertyCreationManager& manager = PropertyCreationManager::instance();
846 switch (chunk_header_.entity_)
847 {
848 case OMFormat::Chunk::Entity_Vertex:
849 {
850 if (_bi.kernel()->_get_vprop(property_name_) == nullptr)
851 manager.create_property<OpenMesh::VertexHandle>(*_bi.kernel(), _property_type, property_name_);
852 break;
853 }
854 case OMFormat::Chunk::Entity_Face:
855 {
856 if (_bi.kernel()->_get_fprop(property_name_) == nullptr)
857 manager.create_property<OpenMesh::FaceHandle>(*_bi.kernel(), _property_type, property_name_);
858 break;
859 }
860 case OMFormat::Chunk::Entity_Edge:
861 {
862 if (_bi.kernel()->_get_eprop(property_name_) == nullptr)
863 manager.create_property<OpenMesh::EdgeHandle>(*_bi.kernel(), _property_type, property_name_);
864 break;
865 }
866 case OMFormat::Chunk::Entity_Halfedge:
867 {
868 if (_bi.kernel()->_get_hprop(property_name_) == nullptr)
869 manager.create_property<OpenMesh::HalfedgeHandle>(*_bi.kernel(), _property_type, property_name_);
870 break;
871 }
872 case OMFormat::Chunk::Entity_Mesh:
873 {
874 if (_bi.kernel()->_get_mprop(property_name_) == nullptr)
875 manager.create_property<OpenMesh::MeshHandle>(*_bi.kernel(), _property_type, property_name_);
876 break;
877 }
878 case OMFormat::Chunk::Entity_Sentinel:
879 ;
880 break;
881 default:
882 ;
883 }
884}
885//-----------------------------------------------------------------------------
886
887//=============================================================================
888} // namespace IO
889} // namespace OpenMesh
890//=============================================================================
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)
Definition Endian.hh:79
static Type local()
Return endian type of host system.
Definition Endian.hh:83
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:77
Set options for reader/writer modules.
Definition Options.hh:92
@ FaceNormal
Has (r) / store (w) face normals.
Definition Options.hh:109
@ Swap
Swap byte order in binary mode.
Definition Options.hh:104
@ FaceColor
Has (r) / store (w) face colors.
Definition Options.hh:110
@ Binary
Set binary mode for r/w.
Definition Options.hh:101
@ Status
Has (r) / store (w) status properties.
Definition Options.hh:115
@ VertexNormal
Has (r) / store (w) vertex normals.
Definition Options.hh:105
@ VertexTexCoord
Has (r) / store (w) texture coordinates.
Definition Options.hh:107
@ VertexColor
Has (r) / store (w) vertex colors.
Definition Options.hh:106
@ Custom
Has (r) / store (w) custom properties marked persistent (currently PLY only supports reading and only...
Definition Options.hh:114
bool register_module(BaseReader *_bl)
Definition IOManager.hh:217
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...
Definition OMReader.cc:235
bool read(const std::string &_filename, BaseImporter &_bi, Options &_opt) override
Definition OMReader.cc:92
static constexpr int dim()
returns dimension of the vector (deprecated)
Definition Vector11T.hh:102
_IOManager_ & IOManager()
Definition IOManager.cc:72
_OMReader_ __OMReaderInstance
Declare the single entity of the OM reader.
Definition OMReader.cc:75
Handle for a edge entity.
Definition Handles.hh:135
Handle for a face entity.
Definition Handles.hh:142
Handle for a halfedge entity.
Definition Handles.hh:128
Handle type for meshes to simplify some template programming.
Definition Handles.hh:149
Handle for a vertex entity.
Definition Handles.hh:121