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 
45 //== INCLUDES =================================================================
46 
47 #include <OpenMesh/Core/System/config.h>
48 // -------------------- STL
49 #if defined( OM_CC_MIPS )
50   #include <time.h>
51   #include <string.h>
52 #else
53   #include <ctime>
54   #include <cstring>
55 #endif
56 
57 #include <fstream>
58 #include <vector>
59 
60 // -------------------- OpenMesh
61 #include <OpenMesh/Core/IO/OMFormat.hh>
62 #include <OpenMesh/Core/IO/exporter/BaseExporter.hh>
63 #include <OpenMesh/Core/IO/writer/OMWriter.hh>
64 
65 //=== NAMESPACES ==============================================================
66 
67 
68 namespace OpenMesh {
69 namespace IO {
70 
71 
72 //=== INSTANCIATE =============================================================
73 
74 
75 // register the OMLoader singleton with MeshLoader
76 _OMWriter_  __OMWriterInstance;
OMWriter()77 _OMWriter_& OMWriter() { return __OMWriterInstance; }
78 
79 
80 //=== IMPLEMENTATION ==========================================================
81 
82 
83 const OMFormat::uchar _OMWriter_::magic_[3] = "OM";
84 const OMFormat::uint8 _OMWriter_::version_  = OMFormat::mk_version(2,1);
85 
86 
87 _OMWriter_::
_OMWriter_()88 _OMWriter_()
89 {
90   IOManager().register_module(this);
91 }
92 
93 
94 bool
write(const std::string & _filename,BaseExporter & _be,Options _opt,std::streamsize) const95 _OMWriter_::write(const std::string& _filename, BaseExporter& _be,
96                    Options _opt, std::streamsize /*_precision*/) const
97 {
98   // check whether exporter can give us an OpenMesh BaseKernel
99   if (!_be.kernel()) return false;
100 
101 
102   // check for om extension in filename, we can only handle OM
103   if (_filename.rfind(".om") == std::string::npos)
104     return false;
105 
106   _opt += Options::Binary; // only binary format supported
107 
108   std::ofstream ofs(_filename.c_str(), std::ios::binary);
109 
110   // check if file is open
111   if (!ofs.is_open())
112   {
113     omerr() << "[OMWriter] : cannot open file " << _filename << std::endl;
114     return false;
115   }
116 
117   // call stream save method
118   bool rc = write(ofs, _be, _opt);
119 
120   // close filestream
121   ofs.close();
122 
123   // return success/failure notice
124   return rc;
125 }
126 
127 
128 //-----------------------------------------------------------------------------
129 
130 bool
write(std::ostream & _os,BaseExporter & _be,Options _opt,std::streamsize) const131 _OMWriter_::write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize /*_precision*/) const
132 {
133 //   std::clog << "[OMWriter]::write( stream )\n";
134 
135   // check exporter features
136   if ( !check( _be, _opt ) )
137   {
138     omerr() << "[OMWriter]: exporter does not support wanted feature!\n";
139     return false;
140   }
141 
142   // Maybe an ascii version will be implemented in the future.
143   // For now, support only a binary format
144   if ( !_opt.check( Options::Binary ) )
145     _opt += Options::Binary;
146 
147   // Ignore LSB/MSB bit. Always store in LSB (little endian)
148   _opt += Options::LSB;
149   _opt -= Options::MSB;
150 
151   return write_binary(_os, _be, _opt);
152 }
153 
154 
155 //-----------------------------------------------------------------------------
156 
157 
158 #ifndef DOXY_IGNORE_THIS
159 template <typename T> struct Enabler
160 {
EnablerOpenMesh::IO::Enabler161   explicit Enabler( T& obj ) : obj_(obj)
162   {}
163 
~EnablerOpenMesh::IO::Enabler164   ~Enabler() { obj_.enable(); }
165 
166   T& obj_;
167 };
168 #endif
169 
170 
write_binary(std::ostream & _os,BaseExporter & _be,Options _opt) const171 bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be,
172                                Options _opt) const
173 {
174   #ifndef DOXY_IGNORE_THIS
175     Enabler<mostream> enabler(omlog());
176   #endif
177 
178   size_t bytes = 0;
179 
180   bool swap = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB);
181 
182   unsigned int i, nV, nF;
183   Vec3f v;
184   Vec3d vd;
185   Vec2f t;
186 
187   // -------------------- write header
188   OMFormat::Header header;
189 
190   header.magic_[0]   = 'O';
191   header.magic_[1]   = 'M';
192   header.mesh_       = _be.is_triangle_mesh() ? 'T' : 'P';
193   header.version_    = version_;
194   header.n_vertices_ = int(_be.n_vertices());
195   header.n_faces_    = int(_be.n_faces());
196   header.n_edges_    = int(_be.n_edges());
197 
198   bytes += store( _os, header, swap );
199 
200   // ---------------------------------------- write chunks
201 
202   OMFormat::Chunk::Header chunk_header;
203 
204 
205   // -------------------- write vertex data
206 
207   // ---------- write vertex position
208   if (_be.n_vertices())
209   {
210     v = _be.point(VertexHandle(0));
211     chunk_header.reserved_ = 0;
212     chunk_header.name_     = false;
213     chunk_header.entity_   = OMFormat::Chunk::Entity_Vertex;
214     chunk_header.type_     = OMFormat::Chunk::Type_Pos;
215     if (_be.is_point_double())
216     {
217       chunk_header.signed_   = OMFormat::is_signed(vd[0]);
218       chunk_header.float_    = OMFormat::is_float(vd[0]);
219       chunk_header.dim_      = OMFormat::dim(vd);
220       chunk_header.bits_     = OMFormat::bits(vd[0]);
221     }
222     else
223     {
224       chunk_header.signed_   = OMFormat::is_signed(v[0]);
225       chunk_header.float_    = OMFormat::is_float(v[0]);
226       chunk_header.dim_      = OMFormat::dim(v);
227       chunk_header.bits_     = OMFormat::bits(v[0]);
228     }
229 
230     bytes += store( _os, chunk_header, swap );
231     if (_be.is_point_double())
232       for (i=0, nV=header.n_vertices_; i<nV; ++i)
233         bytes += vector_store( _os, _be.pointd(VertexHandle(i)), swap );
234     else
235       for (i=0, nV=header.n_vertices_; i<nV; ++i)
236         bytes += vector_store( _os, _be.point(VertexHandle(i)), swap );
237   }
238 
239 
240   // ---------- write vertex normal
241   if (_be.n_vertices() && _opt.check( Options::VertexNormal ))
242   {
243     Vec3f n = _be.normal(VertexHandle(0));
244     Vec3d nd = _be.normald(VertexHandle(0));
245 
246     chunk_header.name_     = false;
247     chunk_header.entity_   = OMFormat::Chunk::Entity_Vertex;
248     chunk_header.type_     = OMFormat::Chunk::Type_Normal;
249     if (_be.is_normal_double())
250     {
251       chunk_header.signed_   = OMFormat::is_signed(nd[0]);
252       chunk_header.float_    = OMFormat::is_float(nd[0]);
253       chunk_header.dim_      = OMFormat::dim(nd);
254       chunk_header.bits_     = OMFormat::bits(nd[0]);
255     }
256     else
257     {
258       chunk_header.signed_   = OMFormat::is_signed(n[0]);
259       chunk_header.float_    = OMFormat::is_float(n[0]);
260       chunk_header.dim_      = OMFormat::dim(n);
261       chunk_header.bits_     = OMFormat::bits(n[0]);
262     }
263 
264     bytes += store( _os, chunk_header, swap );
265     if (_be.is_normal_double())
266       for (i=0, nV=header.n_vertices_; i<nV; ++i)
267         bytes += vector_store( _os, _be.normald(VertexHandle(i)), swap );
268     else
269       for (i=0, nV=header.n_vertices_; i<nV; ++i)
270         bytes += vector_store( _os, _be.normal(VertexHandle(i)), swap );
271 
272   }
273 
274   // ---------- write vertex color
275   if (_be.n_vertices() && _opt.check( Options::VertexColor ) && _be.has_vertex_colors() )
276   {
277     Vec3uc c = _be.color(VertexHandle(0));
278 
279     chunk_header.name_     = false;
280     chunk_header.entity_   = OMFormat::Chunk::Entity_Vertex;
281     chunk_header.type_     = OMFormat::Chunk::Type_Color;
282     chunk_header.signed_   = OMFormat::is_signed( c[0] );
283     chunk_header.float_    = OMFormat::is_float( c[0] );
284     chunk_header.dim_      = OMFormat::dim( c );
285     chunk_header.bits_     = OMFormat::bits( c[0] );
286 
287     bytes += store( _os, chunk_header, swap );
288     for (i=0, nV=header.n_vertices_; i<nV; ++i)
289       bytes += vector_store( _os, _be.color(VertexHandle(i)), swap );
290   }
291 
292   // ---------- write vertex texture coords
293   if (_be.n_vertices() && _opt.check(Options::VertexTexCoord)) {
294 
295     t = _be.texcoord(VertexHandle(0));
296 
297     chunk_header.name_ = false;
298     chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex;
299     chunk_header.type_ = OMFormat::Chunk::Type_Texcoord;
300     chunk_header.signed_ = OMFormat::is_signed(t[0]);
301     chunk_header.float_ = OMFormat::is_float(t[0]);
302     chunk_header.dim_ = OMFormat::dim(t);
303     chunk_header.bits_ = OMFormat::bits(t[0]);
304 
305     // std::clog << chunk_header << std::endl;
306     bytes += store(_os, chunk_header, swap);
307 
308     for (i = 0, nV = header.n_vertices_; i < nV; ++i)
309       bytes += vector_store(_os, _be.texcoord(VertexHandle(i)), swap);
310 
311   }
312 
313   // ---------- wirte halfedge data
314   if (_be.n_edges())
315   {
316     chunk_header.reserved_ = 0;
317     chunk_header.name_     = false;
318     chunk_header.entity_   = OMFormat::Chunk::Entity_Halfedge;
319     chunk_header.type_     = OMFormat::Chunk::Type_Topology;
320     chunk_header.signed_   = true;
321     chunk_header.float_    = true; // TODO: is this correct? This causes a scalar size of 1 in OMFormat.hh scalar_size which we need I think?
322     chunk_header.dim_      = OMFormat::Chunk::Dim_3D;
323     chunk_header.bits_     = OMFormat::needed_bits(_be.n_edges()*4); // *2 due to halfedge ids being stored, *2 due to signedness
324 
325     bytes += store( _os, chunk_header, swap );
326     auto nE=header.n_edges_*2;
327     for (i=0; i<nE; ++i)
328     {
329       auto next_id      = _be.get_next_halfedge_id(HalfedgeHandle(static_cast<int>(i)));
330       auto to_vertex_id = _be.get_to_vertex_id(HalfedgeHandle(static_cast<int>(i)));
331       auto face_id      = _be.get_face_id(HalfedgeHandle(static_cast<int>(i)));
332 
333       bytes += store( _os, next_id,      OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap );
334       bytes += store( _os, to_vertex_id, OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap );
335       bytes += store( _os, face_id,      OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap );
336     }
337   }
338 
339   // ---------- write vertex topology (outgoing halfedge)
340   if (_be.n_vertices())
341   {
342     chunk_header.reserved_ = 0;
343     chunk_header.name_     = false;
344     chunk_header.entity_   = OMFormat::Chunk::Entity_Vertex;
345     chunk_header.type_     = OMFormat::Chunk::Type_Topology;
346     chunk_header.signed_   = true;
347     chunk_header.float_    = true; // TODO: is this correct? This causes a scalar size of 1 in OMFormat.hh scalar_size which we need I think?
348     chunk_header.dim_      = OMFormat::Chunk::Dim_1D;
349     chunk_header.bits_     = OMFormat::needed_bits(_be.n_edges()*4); // *2 due to halfedge ids being stored, *2 due to signedness
350 
351     bytes += store( _os, chunk_header, swap );
352     for (i=0, nV=header.n_vertices_; i<nV; ++i)
353       bytes += store( _os, _be.get_halfedge_id(VertexHandle(i)), OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap );
354   }
355 
356 
357   // -------------------- write face data
358 
359   // ---------- write topology
360   {
361     chunk_header.name_     = false;
362     chunk_header.entity_   = OMFormat::Chunk::Entity_Face;
363     chunk_header.type_     = OMFormat::Chunk::Type_Topology;
364     chunk_header.signed_   = true;
365     chunk_header.float_    = true; // TODO: is this correct? This causes a scalar size of 1 in OMFormat.hh scalar_size which we need I think?
366     chunk_header.dim_      = OMFormat::Chunk::Dim_1D;
367     chunk_header.bits_     = OMFormat::needed_bits(_be.n_edges()*4); // *2 due to halfedge ids being stored, *2 due to signedness
368 
369     bytes += store( _os, chunk_header, swap );
370 
371     for (i=0, nF=header.n_faces_; i<nF; ++i)
372     {
373       auto size = OMFormat::Chunk::Integer_Size(chunk_header.bits_);
374       bytes += store( _os, _be.get_halfedge_id(FaceHandle(i)), size, swap);
375     }
376   }
377 
378   // ---------- write face normals
379 
380   if (_be.n_faces() && _be.has_face_normals() && _opt.check(Options::FaceNormal) )
381   {
382 #define NEW_STYLE 0
383 #if NEW_STYLE
384     const BaseProperty *bp = _be.kernel()._get_fprop("f:normals");
385 
386     if (bp)
387     {
388 #endif
389       Vec3f n = _be.normal(FaceHandle(0));
390       Vec3d nd = _be.normald(FaceHandle(0));
391 
392       chunk_header.name_     = false;
393       chunk_header.entity_   = OMFormat::Chunk::Entity_Face;
394       chunk_header.type_     = OMFormat::Chunk::Type_Normal;
395 
396       if (_be.is_normal_double())
397       {
398         chunk_header.signed_   = OMFormat::is_signed(nd[0]);
399         chunk_header.float_    = OMFormat::is_float(nd[0]);
400         chunk_header.dim_      = OMFormat::dim(nd);
401         chunk_header.bits_     = OMFormat::bits(nd[0]);
402       }
403       else
404       {
405         chunk_header.signed_   = OMFormat::is_signed(n[0]);
406         chunk_header.float_    = OMFormat::is_float(n[0]);
407         chunk_header.dim_      = OMFormat::dim(n);
408         chunk_header.bits_     = OMFormat::bits(n[0]);
409       }
410 
411       bytes += store( _os, chunk_header, swap );
412 #if !NEW_STYLE
413       if (_be.is_normal_double())
414         for (i=0, nF=header.n_faces_; i<nF; ++i)
415           bytes += vector_store( _os, _be.normald(FaceHandle(i)), swap );
416       else
417         for (i=0, nF=header.n_faces_; i<nF; ++i)
418           bytes += vector_store( _os, _be.normal(FaceHandle(i)), swap );
419 
420 #else
421       bytes += bp->store(_os, swap );
422     }
423     else
424       return false;
425 #endif
426 #undef NEW_STYLE
427   }
428 
429 
430   // ---------- write face color
431 
432   if (_be.n_faces() && _be.has_face_colors() && _opt.check( Options::FaceColor ))
433   {
434 #define NEW_STYLE 0
435 #if NEW_STYLE
436     const BaseProperty *bp = _be.kernel()._get_fprop("f:colors");
437 
438     if (bp)
439     {
440 #endif
441       Vec3uc c;
442 
443       chunk_header.name_     = false;
444       chunk_header.entity_   = OMFormat::Chunk::Entity_Face;
445       chunk_header.type_     = OMFormat::Chunk::Type_Color;
446       chunk_header.signed_   = OMFormat::is_signed( c[0] );
447       chunk_header.float_    = OMFormat::is_float( c[0] );
448       chunk_header.dim_      = OMFormat::dim( c );
449       chunk_header.bits_     = OMFormat::bits( c[0] );
450 
451       bytes += store( _os, chunk_header, swap );
452 #if !NEW_STYLE
453       for (i=0, nF=header.n_faces_; i<nF; ++i)
454         bytes += vector_store( _os, _be.color(FaceHandle(i)), swap );
455 #else
456       bytes += bp->store(_os, swap);
457     }
458     else
459       return false;
460 #endif
461   }
462 
463   // ---------- write vertex status
464   if (_be.n_vertices() && _be.has_vertex_status() && _opt.check(Options::Status))
465   {
466     auto s = _be.status(VertexHandle(0));
467     chunk_header.name_ = false;
468     chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex;
469     chunk_header.type_ = OMFormat::Chunk::Type_Status;
470     chunk_header.signed_ = false;
471     chunk_header.float_ = false;
472     chunk_header.dim_ = OMFormat::Chunk::Dim_1D;
473     chunk_header.bits_ = OMFormat::bits(s);
474 
475     // std::clog << chunk_header << std::endl;
476     bytes += store(_os, chunk_header, swap);
477 
478     for (i = 0, nV = header.n_vertices_; i < nV; ++i)
479       bytes += store(_os, _be.status(VertexHandle(i)), swap);
480   }
481 
482   // ---------- write edge status
483   if (_be.n_edges() && _be.has_edge_status() && _opt.check(Options::Status))
484   {
485     auto s = _be.status(EdgeHandle(0));
486     chunk_header.name_ = false;
487     chunk_header.entity_ = OMFormat::Chunk::Entity_Edge;
488     chunk_header.type_ = OMFormat::Chunk::Type_Status;
489     chunk_header.signed_ = false;
490     chunk_header.float_ = false;
491     chunk_header.dim_ = OMFormat::Chunk::Dim_1D;
492     chunk_header.bits_ = OMFormat::bits(s);
493 
494     // std::clog << chunk_header << std::endl;
495     bytes += store(_os, chunk_header, swap);
496 
497     for (i = 0, nV = header.n_edges_; i < nV; ++i)
498       bytes += store(_os, _be.status(EdgeHandle(i)), swap);
499   }
500 
501   // ---------- write halfedge status
502   if (_be.n_edges() && _be.has_halfedge_status() && _opt.check(Options::Status))
503   {
504     auto s = _be.status(HalfedgeHandle(0));
505     chunk_header.name_ = false;
506     chunk_header.entity_ = OMFormat::Chunk::Entity_Halfedge;
507     chunk_header.type_ = OMFormat::Chunk::Type_Status;
508     chunk_header.signed_ = false;
509     chunk_header.float_ = false;
510     chunk_header.dim_ = OMFormat::Chunk::Dim_1D;
511     chunk_header.bits_ = OMFormat::bits(s);
512 
513     // std::clog << chunk_header << std::endl;
514     bytes += store(_os, chunk_header, swap);
515 
516     for (i = 0, nV = header.n_edges_ * 2; i < nV; ++i)
517       bytes += store(_os, _be.status(HalfedgeHandle(i)), swap);
518   }
519 
520   // ---------- write face status
521   if (_be.n_faces() && _be.has_face_status() && _opt.check(Options::Status))
522   {
523     auto s = _be.status(FaceHandle(0));
524     chunk_header.name_ = false;
525     chunk_header.entity_ = OMFormat::Chunk::Entity_Face;
526     chunk_header.type_ = OMFormat::Chunk::Type_Status;
527     chunk_header.signed_ = false;
528     chunk_header.float_ = false;
529     chunk_header.dim_ = OMFormat::Chunk::Dim_1D;
530     chunk_header.bits_ = OMFormat::bits(s);
531 
532     // std::clog << chunk_header << std::endl;
533     bytes += store(_os, chunk_header, swap);
534 
535     for (i = 0, nV = header.n_faces_; i < nV; ++i)
536       bytes += store(_os, _be.status(FaceHandle(i)), swap);
537   }
538 
539   // -------------------- write custom properties
540 
541 
542   BaseKernel::const_prop_iterator prop;
543 
544   for (prop  = _be.kernel()->vprops_begin();
545        prop != _be.kernel()->vprops_end(); ++prop)
546   {
547     if ( !*prop ) continue;
548     if ( (*prop)->name()[1]==':') continue;
549     bytes += store_binary_custom_chunk(_os, **prop,
550 				       OMFormat::Chunk::Entity_Vertex, swap );
551   }
552   for (prop  = _be.kernel()->fprops_begin();
553        prop != _be.kernel()->fprops_end(); ++prop)
554   {
555     if ( !*prop ) continue;
556     if ( (*prop)->name()[1]==':') continue;
557     bytes += store_binary_custom_chunk(_os, **prop,
558 				       OMFormat::Chunk::Entity_Face, swap );
559   }
560   for (prop  = _be.kernel()->eprops_begin();
561        prop != _be.kernel()->eprops_end(); ++prop)
562   {
563     if ( !*prop ) continue;
564     if ( (*prop)->name()[1]==':') continue;
565     bytes += store_binary_custom_chunk(_os, **prop,
566 				       OMFormat::Chunk::Entity_Edge, swap );
567   }
568   for (prop  = _be.kernel()->hprops_begin();
569        prop != _be.kernel()->hprops_end(); ++prop)
570   {
571     if ( !*prop ) continue;
572     if ( (*prop)->name()[1]==':') continue;
573     bytes += store_binary_custom_chunk(_os, **prop,
574 				       OMFormat::Chunk::Entity_Halfedge, swap );
575   }
576   for (prop  = _be.kernel()->mprops_begin();
577        prop != _be.kernel()->mprops_end(); ++prop)
578   {
579     if ( !*prop ) continue;
580     if ( (*prop)->name()[1]==':') continue;
581     bytes += store_binary_custom_chunk(_os, **prop,
582 				       OMFormat::Chunk::Entity_Mesh, swap );
583   }
584 
585   memset(&chunk_header, 0, sizeof(chunk_header));
586   chunk_header.name_ = false;
587   chunk_header.entity_ = OMFormat::Chunk::Entity_Sentinel;
588   bytes += store(_os, chunk_header, swap);
589 
590   std::clog << "#bytes written: " << bytes << std::endl;
591 
592   return true;
593 }
594 
595 // ----------------------------------------------------------------------------
596 
store_binary_custom_chunk(std::ostream & _os,const BaseProperty & _bp,OMFormat::Chunk::Entity _entity,bool _swap) const597 size_t _OMWriter_::store_binary_custom_chunk(std::ostream& _os,
598 					     const BaseProperty& _bp,
599 					     OMFormat::Chunk::Entity _entity,
600 					     bool _swap) const
601 {
602   //omlog() << "Custom Property " << OMFormat::as_string(_entity) << " property ["
603   //	<< _bp.name() << "]" << std::endl;
604 
605   // Don't store if
606   // 1. it is not persistent
607   // 2. it's name is empty
608   if ( !_bp.persistent() || _bp.name().empty() )
609   {
610     //omlog() << "  skipped\n";
611     return 0;
612   }
613 
614   size_t bytes = 0;
615 
616   OMFormat::Chunk::esize_t element_size   = OMFormat::Chunk::esize_t(_bp.element_size());
617   OMFormat::Chunk::Header  chdr;
618 
619   // set header
620   chdr.name_     = true;
621   chdr.entity_   = _entity;
622   chdr.type_     = OMFormat::Chunk::Type_Custom;
623   chdr.signed_   = 0;
624   chdr.float_    = 0;
625   chdr.dim_      = OMFormat::Chunk::Dim_1D; // ignored
626   chdr.bits_     = element_size;
627 
628 
629   // write custom chunk
630 
631   // 1. chunk header
632   bytes += store( _os, chdr, _swap );
633 
634   // 2. property name
635   bytes += store( _os, OMFormat::Chunk::PropertyName(_bp.name()), _swap );
636 
637   // 3. block size
638   bytes += store( _os, _bp.size_of(), OMFormat::Chunk::Integer_32, _swap );
639   //omlog() << "  n_bytes = " << _bp.size_of() << std::endl;
640 
641   // 4. data
642   {
643     size_t b;
644     bytes += ( b=_bp.store( _os, _swap ) );
645     //omlog() << "  b       = " << b << std::endl;
646     assert( b == _bp.size_of() );
647   }
648   return bytes;
649 }
650 
651 // ----------------------------------------------------------------------------
652 
binary_size(BaseExporter &,Options) const653 size_t _OMWriter_::binary_size(BaseExporter& /* _be */, Options /* _opt */) const
654 {
655   // std::clog << "[OMWriter]: binary_size()" << std::endl;
656   size_t bytes  = sizeof( OMFormat::Header );
657 
658   // !!!TODO!!!
659 
660   return bytes;
661 }
662 
663 //=============================================================================
664 } // namespace IO
665 } // namespace OpenMesh
666 //=============================================================================
667