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