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