Developer Documentation
 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 
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
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 
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 //=============================================================================
_OMWriter_()
Constructor.
Definition: OMWriter.cc:93
Has (r) / store (w) vertex normals.
Definition: Options.hh:109
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:222
Has (r) / store (w) face normals.
Definition: Options.hh:113
Assume big endian byte ordering.
Definition: Options.hh:106
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
Has (r) / store (w) face colors.
Definition: Options.hh:114
bool write(std::ostream &, BaseExporter &, Options, std::streamsize _precision=6) const
Definition: OMWriter.cc:136
Has (r) / store (w) texture coordinates.
Definition: Options.hh:111
Set options for reader/writer modules.
Definition: Options.hh:95
static Type local()
Return endian type of host system.
Definition: Endian.hh:88
big endian (Motorola's 68x family, DEC Alpha, MIPS)
Definition: Endian.hh:84
Set binary mode for r/w.
Definition: Options.hh:105
Swap byte order in binary mode.
Definition: Options.hh:108
Has (r) / store (w) vertex colors.
Definition: Options.hh:110
Assume little endian byte ordering.
Definition: Options.hh:107
_OMWriter_ __OMWriterInstance
Declare the single entity of the OM writer.
Definition: OMWriter.cc:81
_IOManager_ & IOManager()
Definition: IOManager.cc:77