Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
OMWriter.cc
1 /* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openmesh.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenMesh. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 * ========================================================================= */
41
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $Date$ *
46 * *
47 \*===========================================================================*/
48
49
50 //== INCLUDES =================================================================
51
52 #include <OpenMesh/Core/System/config.h>
53 // -------------------- STL
54 #if defined( OM_CC_MIPS )
55 #include <time.h>
56 #include <string.h>
57 #else
58 #include <ctime>
59 #include <cstring>
60 #endif
61
62 #include <fstream>
63 #include <vector>
64
65 // -------------------- OpenMesh
66 #include <OpenMesh/Core/IO/OMFormat.hh>
67 #include <OpenMesh/Core/IO/exporter/BaseExporter.hh>
68 #include <OpenMesh/Core/IO/writer/OMWriter.hh>
69
70 //=== NAMESPACES ==============================================================
71
72
73 namespace OpenMesh {
74 namespace IO {
75
76
77 //=== INSTANCIATE =============================================================
78
79
80 // register the OMLoader singleton with MeshLoader
81 _OMWriter_ __OMWriterInstance;
82 _OMWriter_& OMWriter() { return __OMWriterInstance; }
83
84
85 //=== IMPLEMENTATION ==========================================================
86
87
88 const OMFormat::uchar _OMWriter_::magic_[3] = "OM";
89 const OMFormat::uint8 _OMWriter_::version_ = OMFormat::mk_version(1,2);
90
91
92 _OMWriter_::
93 _OMWriter_()
94 {
95 IOManager().register_module(this);
96 }
97
98
99 bool
100 _OMWriter_::write(const std::string& _filename, BaseExporter& _be,
101 Options _opt, std::streamsize /*_precision*/) const
102 {
103 // check whether exporter can give us an OpenMesh BaseKernel
104 if (!_be.kernel()) return false;
105
106
107 // check for om extension in filename, we can only handle OM
108 if (_filename.rfind(".om") == std::string::npos)
109 return false;
110
111 _opt += Options::Binary; // only binary format supported
112
113 std::ofstream ofs(_filename.c_str(), std::ios::binary);
114
115 // check if file is open
116 if (!ofs.is_open())
117 {
118 omerr() << "[OMWriter] : cannot open file " << _filename << std::endl;
119 return false;
120 }
121
122 // call stream save method
123 bool rc = write(ofs, _be, _opt);
124
125 // close filestream
126 ofs.close();
127
128 // return success/failure notice
129 return rc;
130 }
131
132
133 //-----------------------------------------------------------------------------
134
135 bool
136 _OMWriter_::write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize /*_precision*/) const
137 {
138 // std::clog << "[OMWriter]::write( stream )\n";
139
140 // check exporter features
141 if ( !check( _be, _opt ) )
142 {
143 omerr() << "[OMWriter]: exporter does not support wanted feature!\n";
144 return false;
145 }
146
147 // Maybe an ascii version will be implemented in the future.
148 // For now, support only a binary format
149 if ( !_opt.check( Options::Binary ) )
150 _opt += Options::Binary;
151
152 // Ignore LSB/MSB bit. Always store in LSB (little endian)
153 _opt += Options::LSB;
154 _opt -= Options::MSB;
155
156 return write_binary(_os, _be, _opt);
157 }
158
159
160 //-----------------------------------------------------------------------------
161
162
163 #ifndef DOXY_IGNORE_THIS
164 template <typename T> struct Enabler
165 {
166 Enabler( T& obj ) : obj_(obj)
167 {}
168
169 ~Enabler() { obj_.enable(); }
170
171 T& obj_;
172 };
173 #endif
174
175
176 bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be,
177 Options _opt) const
178 {
179 #ifndef DOXY_IGNORE_THIS
180 Enabler<mostream> enabler(omlog());
181 #endif
182
183 size_t bytes = 0;
184
185 bool swap = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB);
186
187 unsigned int i, nV, nF;
188 Vec3f v;
189 Vec2f t;
190 std::vector<VertexHandle> vhandles;
191
192
193 // -------------------- write header
194 OMFormat::Header header;
195
196 header.magic_[0] = 'O';
197 header.magic_[1] = 'M';
198 header.mesh_ = _be.is_triangle_mesh() ? 'T' : 'P';
199 header.version_ = version_;
200 header.n_vertices_ = int(_be.n_vertices());
201 header.n_faces_ = int(_be.n_faces());
202 header.n_edges_ = int(_be.n_edges());
203
204 bytes += store( _os, header, swap );
205
206 // ---------------------------------------- write chunks
207
208 OMFormat::Chunk::Header chunk_header;
209
210
211 // -------------------- write vertex data
212
213 // ---------- write vertex position
214 if (_be.n_vertices())
215 {
216 v = _be.point(VertexHandle(0));
217 chunk_header.reserved_ = 0;
218 chunk_header.name_ = false;
219 chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex;
220 chunk_header.type_ = OMFormat::Chunk::Type_Pos;
221 chunk_header.signed_ = OMFormat::is_signed(v[0]);
222 chunk_header.float_ = OMFormat::is_float(v[0]);
223 chunk_header.dim_ = OMFormat::dim(v);
224 chunk_header.bits_ = OMFormat::bits(v[0]);
225
226 bytes += store( _os, chunk_header, swap );
227 for (i=0, nV=header.n_vertices_; i<nV; ++i)
228 bytes += vector_store( _os, _be.point(VertexHandle(i)), swap );
229 }
230
231
232 // ---------- write vertex normal
233 if (_be.n_vertices() && _opt.check( Options::VertexNormal ))
234 {
235 Vec3f n = _be.normal(VertexHandle(0));
236
237 chunk_header.name_ = false;
238 chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex;
239 chunk_header.type_ = OMFormat::Chunk::Type_Normal;
240 chunk_header.signed_ = OMFormat::is_signed(n[0]);
241 chunk_header.float_ = OMFormat::is_float(n[0]);
242 chunk_header.dim_ = OMFormat::dim(n);
243 chunk_header.bits_ = OMFormat::bits(n[0]);
244
245 bytes += store( _os, chunk_header, swap );
246 for (i=0, nV=header.n_vertices_; i<nV; ++i)
247 bytes += vector_store( _os, _be.normal(VertexHandle(i)), swap );
248 }
249
250 // ---------- write vertex color
251 if (_be.n_vertices() && _opt.check( Options::VertexColor ) && _be.has_vertex_colors() )
252 {
253 Vec3uc c = _be.color(VertexHandle(0));
254
255 chunk_header.name_ = false;
256 chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex;
257 chunk_header.type_ = OMFormat::Chunk::Type_Color;
258 chunk_header.signed_ = OMFormat::is_signed( c[0] );
259 chunk_header.float_ = OMFormat::is_float( c[0] );
260 chunk_header.dim_ = OMFormat::dim( c );
261 chunk_header.bits_ = OMFormat::bits( c[0] );
262
263 bytes += store( _os, chunk_header, swap );
264 for (i=0, nV=header.n_vertices_; i<nV; ++i)
265 bytes += vector_store( _os, _be.color(VertexHandle(i)), swap );
266 }
267
268 // ---------- write vertex texture coords
269 if (_be.n_vertices() && _opt.check(Options::VertexTexCoord)) {
270
271 t = _be.texcoord(VertexHandle(0));
272
273 chunk_header.name_ = false;
274 chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex;
275 chunk_header.type_ = OMFormat::Chunk::Type_Texcoord;
276 chunk_header.signed_ = OMFormat::is_signed(t[0]);
277 chunk_header.float_ = OMFormat::is_float(t[0]);
278 chunk_header.dim_ = OMFormat::dim(t);
279 chunk_header.bits_ = OMFormat::bits(t[0]);
280
281 // std::clog << chunk_header << std::endl;
282 bytes += store(_os, chunk_header, swap);
283
284 for (i = 0, nV = header.n_vertices_; i < nV; ++i)
285 bytes += vector_store(_os, _be.texcoord(VertexHandle(i)), swap);
286
287 }
288
289 // -------------------- write face data
290
291 // ---------- write topology
292 {
293 chunk_header.name_ = false;
294 chunk_header.entity_ = OMFormat::Chunk::Entity_Face;
295 chunk_header.type_ = OMFormat::Chunk::Type_Topology;
296 chunk_header.signed_ = 0;
297 chunk_header.float_ = 0;
298 chunk_header.dim_ = OMFormat::Chunk::Dim_1D; // ignored
299 chunk_header.bits_ = OMFormat::needed_bits(_be.n_vertices());
300
301 bytes += store( _os, chunk_header, swap );
302
303 for (i=0, nF=header.n_faces_; i<nF; ++i)
304 {
305 nV = _be.get_vhandles(FaceHandle(i), vhandles);
306 if ( header.mesh_ == 'P' )
307 bytes += store( _os, vhandles.size(), OMFormat::Chunk::Integer_16, swap );
308
309 for (size_t j=0; j < vhandles.size(); ++j)
310 {
311 using namespace OMFormat;
312 using namespace GenProg;
313
314 bytes += store( _os, vhandles[j].idx(), Chunk::Integer_Size(chunk_header.bits_), swap );
315 }
316 }
317 }
318
319 // ---------- write face normals
320
321 if ( _be.has_face_normals() && _opt.check(Options::FaceNormal) )
322 {
323 #define NEW_STYLE 0
324 #if NEW_STYLE
325 const BaseProperty *bp = _be.kernel()._get_fprop("f:normals");
326
327 if (bp)
328 {
329 #endif
330 Vec3f n = _be.normal(FaceHandle(0));
331
332 chunk_header.name_ = false;
333 chunk_header.entity_ = OMFormat::Chunk::Entity_Face;
334 chunk_header.type_ = OMFormat::Chunk::Type_Normal;
335 chunk_header.signed_ = OMFormat::is_signed(n[0]);
336 chunk_header.float_ = OMFormat::is_float(n[0]);
337 chunk_header.dim_ = OMFormat::dim(n);
338 chunk_header.bits_ = OMFormat::bits(n[0]);
339
340 bytes += store( _os, chunk_header, swap );
341 #if !NEW_STYLE
342 for (i=0, nF=header.n_faces_; i<nF; ++i)
343 bytes += vector_store( _os, _be.normal(FaceHandle(i)), swap );
344 #else
345 bytes += bp->store(_os, swap );
346 }
347 else
348 return false;
349 #endif
350 #undef NEW_STYLE
351 }
352
353
354 // ---------- write face color
355
356 if (_be.has_face_colors() && _opt.check( Options::FaceColor ))
357 {
358 #define NEW_STYLE 0
359 #if NEW_STYLE
360 const BaseProperty *bp = _be.kernel()._get_fprop("f:colors");
361
362 if (bp)
363 {
364 #endif
365 Vec3uc c;
366
367 chunk_header.name_ = false;
368 chunk_header.entity_ = OMFormat::Chunk::Entity_Face;
369 chunk_header.type_ = OMFormat::Chunk::Type_Color;
370 chunk_header.signed_ = OMFormat::is_signed( c[0] );
371 chunk_header.float_ = OMFormat::is_float( c[0] );
372 chunk_header.dim_ = OMFormat::dim( c );
373 chunk_header.bits_ = OMFormat::bits( c[0] );
374
375 bytes += store( _os, chunk_header, swap );
376 #if !NEW_STYLE
377 for (i=0, nF=header.n_faces_; i<nF; ++i)
378 bytes += vector_store( _os, _be.color(FaceHandle(i)), swap );
379 #else
380 bytes += bp->store(_os, swap);
381 }
382 else
383 return false;
384 #endif
385 }
386
387 // -------------------- write custom properties
388
389
390 BaseKernel::const_prop_iterator prop;
391
392 for (prop = _be.kernel()->vprops_begin();
393 prop != _be.kernel()->vprops_end(); ++prop)
394 {
395 if ( !*prop ) continue;
396 if ( (*prop)->name()[1]==':') continue;
397 bytes += store_binary_custom_chunk(_os, **prop,
398 OMFormat::Chunk::Entity_Vertex, swap );
399 }
400 for (prop = _be.kernel()->fprops_begin();
401 prop != _be.kernel()->fprops_end(); ++prop)
402 {
403 if ( !*prop ) continue;
404 if ( (*prop)->name()[1]==':') continue;
405 bytes += store_binary_custom_chunk(_os, **prop,
406 OMFormat::Chunk::Entity_Face, swap );
407 }
408 for (prop = _be.kernel()->eprops_begin();
409 prop != _be.kernel()->eprops_end(); ++prop)
410 {
411 if ( !*prop ) continue;
412 if ( (*prop)->name()[1]==':') continue;
413 bytes += store_binary_custom_chunk(_os, **prop,
414 OMFormat::Chunk::Entity_Edge, swap );
415 }
416 for (prop = _be.kernel()->hprops_begin();
417 prop != _be.kernel()->hprops_end(); ++prop)
418 {
419 if ( !*prop ) continue;
420 if ( (*prop)->name()[1]==':') continue;
421 bytes += store_binary_custom_chunk(_os, **prop,
422 OMFormat::Chunk::Entity_Halfedge, swap );
423 }
424 for (prop = _be.kernel()->mprops_begin();
425 prop != _be.kernel()->mprops_end(); ++prop)
426 {
427 if ( !*prop ) continue;
428 if ( (*prop)->name()[1]==':') continue;
429 bytes += store_binary_custom_chunk(_os, **prop,
430 OMFormat::Chunk::Entity_Mesh, swap );
431 }
432
433 std::clog << "#bytes written: " << bytes << std::endl;
434
435 return true;
436 }
437
438 // ----------------------------------------------------------------------------
439
440 size_t _OMWriter_::store_binary_custom_chunk(std::ostream& _os,
441 const BaseProperty& _bp,
442 OMFormat::Chunk::Entity _entity,
443 bool _swap) const
444 {
445 //omlog() << "Custom Property " << OMFormat::as_string(_entity) << " property ["
446 // << _bp.name() << "]" << std::endl;
447
448 // Don't store if
449 // 1. it is not persistent
450 // 2. it's name is empty
451 if ( !_bp.persistent() || _bp.name().empty() )
452 {
453 //omlog() << " skipped\n";
454 return 0;
455 }
456
457 size_t bytes = 0;
458
459 OMFormat::Chunk::esize_t element_size = OMFormat::Chunk::esize_t(_bp.element_size());
460 OMFormat::Chunk::Header chdr;
461
462 // set header
463 chdr.name_ = true;
464 chdr.entity_ = _entity;
465 chdr.type_ = OMFormat::Chunk::Type_Custom;
466 chdr.signed_ = 0;
467 chdr.float_ = 0;
468 chdr.dim_ = OMFormat::Chunk::Dim_1D; // ignored
469 chdr.bits_ = element_size;
470
471
472 // write custom chunk
473
474 // 1. chunk header
475 bytes += store( _os, chdr, _swap );
476
477 // 2. property name
478 bytes += store( _os, OMFormat::Chunk::PropertyName(_bp.name()), _swap );
479
480 // 3. block size
481 bytes += store( _os, _bp.size_of(), OMFormat::Chunk::Integer_32, _swap );
482 //omlog() << " n_bytes = " << _bp.size_of() << std::endl;
483
484 // 4. data
485 {
486 size_t b;
487 bytes += ( b=_bp.store( _os, _swap ) );
488 //omlog() << " b = " << b << std::endl;
489 assert( b == _bp.size_of() );
490 }
491 return bytes;
492 }
493
494 // ----------------------------------------------------------------------------
495
496 size_t _OMWriter_::binary_size(BaseExporter& /* _be */, Options /* _opt */) const
497 {
498 // std::clog << "[OMWriter]: binary_size()" << std::endl;
499 size_t bytes = sizeof( OMFormat::Header );
500
501 // !!!TODO!!!
502
503 return bytes;
504 }
505
506 //=============================================================================
507 } // namespace IO
508 } // namespace OpenMesh
509 //=============================================================================
OpenMesh::IO::_OMWriter_::_OMWriter_
_OMWriter_()
Constructor.
Definition: OMWriter.cc:93
OpenMesh::IO::Options::VertexNormal
Has (r) / store (w) vertex normals.
Definition: Options.hh:109
OpenMesh
Definition: MeshItems.hh:64
OpenMesh::IO::_IOManager_::register_module
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:222
OpenMesh::IO::Options::FaceNormal
Has (r) / store (w) face normals.
Definition: Options.hh:113
OpenMesh::IO::Options::MSB
Assume big endian byte ordering.
Definition: Options.hh:106
OpenMesh::IO::_OMWriter_::binary_size
size_t binary_size(BaseExporter &_be, Options _opt) const
Returns expected size of file if binary format is supported else 0.
Definition: OMWriter.cc:496
OpenMesh::IO::Options::FaceColor
Has (r) / store (w) face colors.
Definition: Options.hh:114
OpenMesh::IO::_OMWriter_::write
bool write(std::ostream &, BaseExporter &, Options, std::streamsize _precision=6) const
Definition: OMWriter.cc:136
OpenMesh::IO::Options::VertexTexCoord
Has (r) / store (w) texture coordinates.
Definition: Options.hh:111
OpenMesh::IO::Options
Set options for reader/writer modules.
Definition: Options.hh:95
OpenMesh::Endian::local
static Type local()
Return endian type of host system.
Definition: Endian.hh:88
OpenMesh::Endian::MSB
big endian (Motorola's 68x family, DEC Alpha, MIPS)
Definition: Endian.hh:84
config.h
OpenMesh::IO::BaseExporter
Definition: BaseExporter.hh:89
OpenMesh::VectorT< float, 2 >
OpenMesh::IO::_OMWriter_
Definition: OMWriter.hh:96
OpenMesh::IO::Options::Binary
Set binary mode for r/w.
Definition: Options.hh:105
OpenMesh::IO::Options::Swap
Swap byte order in binary mode.
Definition: Options.hh:108
OpenMesh::IO::Options::VertexColor
Has (r) / store (w) vertex colors.
Definition: Options.hh:110
OpenMesh::IO::Options::LSB
Assume little endian byte ordering.
Definition: Options.hh:107
OpenVolumeMesh::Geometry::VectorT
Definition: Vector11T.hh:78
OpenMesh::IO::__OMWriterInstance
_OMWriter_ __OMWriterInstance
Declare the single entity of the OM writer.
Definition: OMWriter.cc:81
BaseExporter
Definition: BaseExporter.hh:1
OpenMesh::IO::IOManager
_IOManager_ & IOManager()
Definition: IOManager.cc:77