Developer Documentation
OFFWriter.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 <fstream>
55 #include <OpenMesh/Core/Utils/Endian.hh>
56 #include <OpenMesh/Core/IO/IOManager.hh>
57 #include <OpenMesh/Core/IO/BinaryHelper.hh>
58 #include <OpenMesh/Core/IO/writer/OFFWriter.hh>
59 
60 //=== NAMESPACES ==============================================================
61 
62 
63 namespace OpenMesh {
64 namespace IO {
65 
66 
67 //=== INSTANCIATE =============================================================
68 
69 
70 // register the OFFLoader singleton with MeshLoader
72 _OFFWriter_& OFFWriter() { return __OFFWriterInstance; }
73 
74 
75 //=== IMPLEMENTATION ==========================================================
76 
77 
78 _OFFWriter_::_OFFWriter_() { IOManager().register_module(this); }
79 
80 
81 //-----------------------------------------------------------------------------
82 
83 
84 bool
86 write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) const
87 {
88  std::ofstream out(_filename.c_str(), (_opt.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out
89  : std::ios_base::out) );
90 
91  return write(out, _be, _opt, _precision);
92 }
93 
94 //-----------------------------------------------------------------------------
95 
96 
97 bool
99 write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize _precision) const
100 {
101  // check exporter features
102  if ( !check( _be, _opt ) )
103  return false;
104 
105 
106  // check writer features
107  if ( _opt.check(Options::FaceNormal) ) // not supported by format
108  return false;
109 
110 
111  if (!_os.good())
112  {
113  omerr() << "[OFFWriter] : cannot write to stream "
114  << std::endl;
115  return false;
116  }
117 
118  // write header line
119  if (_opt.check(Options::VertexTexCoord)) _os << "ST";
120  if (_opt.check(Options::VertexColor) || _opt.check(Options::FaceColor)) _os << "C";
121  if (_opt.check(Options::VertexNormal)) _os << "N";
122  _os << "OFF";
123  if (_opt.check(Options::Binary)) _os << " BINARY";
124  _os << "\n";
125 
126  if (!_opt.check(Options::Binary))
127  _os.precision(_precision);
128 
129  // write to file
130  bool result = (_opt.check(Options::Binary) ?
131  write_binary(_os, _be, _opt) :
132  write_ascii(_os, _be, _opt));
133 
134 
135  // return result
136  return result;
137 }
138 
139 //-----------------------------------------------------------------------------
140 
141 
142 bool
143 _OFFWriter_::
144 write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const
145 {
146 
147  unsigned int i, nV, nF;
148  Vec3f v, n;
149  Vec2f t;
150  OpenMesh::Vec3i c;
151  OpenMesh::Vec4i cA;
152  OpenMesh::Vec3f cf;
153  OpenMesh::Vec4f cAf;
154  VertexHandle vh;
155  std::vector<VertexHandle> vhandles;
156 
157 
158  // #vertices, #faces
159  _out << _be.n_vertices() << " ";
160  _out << _be.n_faces() << " ";
161  _out << 0 << "\n";
162 
163  if (_opt.color_is_float())
164  _out << std::fixed;
165 
166 
167  // vertex data (point, normals, colors, texcoords)
168  for (i=0, nV=int(_be.n_vertices()); i<nV; ++i)
169  {
170  vh = VertexHandle(i);
171  v = _be.point(vh);
172 
173  //Vertex
174  _out << v[0] << " " << v[1] << " " << v[2];
175 
176  // VertexNormal
177  if ( _opt.vertex_has_normal() ) {
178  n = _be.normal(vh);
179  _out << " " << n[0] << " " << n[1] << " " << n[2];
180  }
181 
182  // VertexColor
183  if ( _opt.vertex_has_color() ) {
184  if ( _opt.color_is_float() ) {
185  //with alpha
186  if ( _opt.color_has_alpha() ){
187  cAf = _be.colorAf(vh);
188  _out << " " << cAf;
189  }else{
190  //without alpha
191  cf = _be.colorf(vh);
192  _out << " " << cf;
193  }
194  } else {
195  //with alpha
196  if ( _opt.color_has_alpha() ){
197  cA = _be.colorA(vh);
198  _out << " " << cA;
199  }else{
200  //without alpha
201  c = _be.color(vh);
202  _out << " " << c;
203  }
204  }
205  }
206 
207  // TexCoord
208  if (_opt.vertex_has_texcoord() ) {
209  t = _be.texcoord(vh);
210  _out << " " << t[0] << " " << t[1];
211  }
212 
213  _out << '\n';
214 
215  }
216 
217  // faces (indices starting at 0)
218  if (_be.is_triangle_mesh())
219  {
220  for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
221  {
222  _be.get_vhandles(FaceHandle(i), vhandles);
223  _out << 3 << " ";
224  _out << vhandles[0].idx() << " ";
225  _out << vhandles[1].idx() << " ";
226  _out << vhandles[2].idx();
227 
228  //face color
229  if ( _opt.face_has_color() ){
230  if ( _opt.color_is_float() ) {
231  //with alpha
232  if ( _opt.color_has_alpha() ){
233  cAf = _be.colorAf( FaceHandle(i) );
234  _out << " " << cAf;
235  }else{
236  //without alpha
237  cf = _be.colorf( FaceHandle(i) );
238  _out << " " << cf;
239  }
240  } else {
241  //with alpha
242  if ( _opt.color_has_alpha() ){
243  cA = _be.colorA( FaceHandle(i) );
244  _out << " " << cA;
245  }else{
246  //without alpha
247  c = _be.color( FaceHandle(i) );
248  _out << " " << c;
249  }
250  }
251  }
252  _out << '\n';
253  }
254  }
255  else
256  {
257  for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
258  {
259  nV = _be.get_vhandles(FaceHandle(i), vhandles);
260  _out << nV << " ";
261  for (size_t j=0; j<vhandles.size(); ++j)
262  _out << vhandles[j].idx() << " ";
263 
264  //face color
265  if ( _opt.face_has_color() ){
266  if ( _opt.color_is_float() ) {
267  //with alpha
268  if ( _opt.color_has_alpha() ){
269  cAf = _be.colorAf( FaceHandle(i) );
270  _out << " " << cAf;
271  }else{
272  //without alpha
273  cf = _be.colorf( FaceHandle(i) );
274  _out << " " << cf;
275  }
276  } else {
277  //with alpha
278  if ( _opt.color_has_alpha() ){
279  cA = _be.colorA( FaceHandle(i) );
280  _out << " " << cA;
281  }else{
282  //without alpha
283  c = _be.color( FaceHandle(i) );
284  _out << " " << c;
285  }
286  }
287  }
288 
289  _out << '\n';
290  }
291  }
292 
293 
294  return true;
295 }
296 
297 
298 //-----------------------------------------------------------------------------
299 
300 void _OFFWriter_::writeValue(std::ostream& _out, int value) const {
301 
302  uint32_t tmp = value;
303  store(_out, tmp, false);
304 }
305 
306 void _OFFWriter_::writeValue(std::ostream& _out, unsigned int value) const {
307 
308  uint32_t tmp = value;
309  store(_out, tmp, false);
310 }
311 
312 void _OFFWriter_::writeValue(std::ostream& _out, float value) const {
313 
314  float32_t tmp = value;
315  store(_out, tmp, false);
316 }
317 
318 bool
319 _OFFWriter_::
320 write_binary(std::ostream& _out, BaseExporter& _be, Options _opt) const
321 {
322 
323  unsigned int i, nV, nF;
324  Vec3f v, n;
325  Vec2f t;
326  OpenMesh::Vec4i c;
327  OpenMesh::Vec4f cf;
328  VertexHandle vh;
329  std::vector<VertexHandle> vhandles;
330 
331  // #vertices, #faces
332  writeValue(_out, (uint)_be.n_vertices() );
333  writeValue(_out, (uint) _be.n_faces() );
334  writeValue(_out, 0 );
335 
336  // vertex data (point, normals, texcoords)
337  for (i=0, nV=int(_be.n_vertices()); i<nV; ++i)
338  {
339  vh = VertexHandle(i);
340  v = _be.point(vh);
341 
342  //vertex
343  writeValue(_out, v[0]);
344  writeValue(_out, v[1]);
345  writeValue(_out, v[2]);
346 
347  // vertex normal
348  if ( _opt.vertex_has_normal() ) {
349  n = _be.normal(vh);
350  writeValue(_out, n[0]);
351  writeValue(_out, n[1]);
352  writeValue(_out, n[2]);
353  }
354  // vertex color
355  if ( _opt.vertex_has_color() ) {
356  if ( _opt.color_is_float() ) {
357  cf = _be.colorAf(vh);
358  writeValue(_out, cf[0]);
359  writeValue(_out, cf[1]);
360  writeValue(_out, cf[2]);
361 
362  if ( _opt.color_has_alpha() )
363  writeValue(_out, cf[3]);
364  } else {
365  c = _be.colorA(vh);
366  writeValue(_out, c[0]);
367  writeValue(_out, c[1]);
368  writeValue(_out, c[2]);
369 
370  if ( _opt.color_has_alpha() )
371  writeValue(_out, c[3]);
372  }
373  }
374  // texCoords
375  if (_opt.vertex_has_texcoord() ) {
376  t = _be.texcoord(vh);
377  writeValue(_out, t[0]);
378  writeValue(_out, t[1]);
379  }
380 
381  }
382 
383  // faces (indices starting at 0)
384  if (_be.is_triangle_mesh())
385  {
386  for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
387  {
388  //face
389  _be.get_vhandles(FaceHandle(i), vhandles);
390  writeValue(_out, 3);
391  writeValue(_out, vhandles[0].idx());
392  writeValue(_out, vhandles[1].idx());
393  writeValue(_out, vhandles[2].idx());
394 
395  //face color
396  if ( _opt.face_has_color() ){
397  if ( _opt.color_is_float() ) {
398  cf = _be.colorAf( FaceHandle(i) );
399  writeValue(_out, cf[0]);
400  writeValue(_out, cf[1]);
401  writeValue(_out, cf[2]);
402 
403  if ( _opt.color_has_alpha() )
404  writeValue(_out, cf[3]);
405  } else {
406  c = _be.colorA( FaceHandle(i) );
407  writeValue(_out, c[0]);
408  writeValue(_out, c[1]);
409  writeValue(_out, c[2]);
410 
411  if ( _opt.color_has_alpha() )
412  writeValue(_out, c[3]);
413  }
414  }
415  }
416  }
417  else
418  {
419  for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
420  {
421  //face
422  nV = _be.get_vhandles(FaceHandle(i), vhandles);
423  writeValue(_out, nV);
424  for (size_t j=0; j<vhandles.size(); ++j)
425  writeValue(_out, vhandles[j].idx() );
426 
427  //face color
428  if ( _opt.face_has_color() ){
429  if ( _opt.color_is_float() ) {
430  cf = _be.colorAf( FaceHandle(i) );
431  writeValue(_out, cf[0]);
432  writeValue(_out, cf[1]);
433  writeValue(_out, cf[2]);
434 
435  if ( _opt.color_has_alpha() )
436  writeValue(_out, cf[3]);
437  } else {
438  c = _be.colorA( FaceHandle(i) );
439  writeValue(_out, c[0]);
440  writeValue(_out, c[1]);
441  writeValue(_out, c[2]);
442 
443  if ( _opt.color_has_alpha() )
444  writeValue(_out, c[3]);
445  }
446  }
447  }
448  }
449 
450  return true;
451 }
452 
453 // ----------------------------------------------------------------------------
454 
455 
456 size_t
459 {
460  size_t header(0);
461  size_t data(0);
462 
463  size_t _3floats(3*sizeof(float));
464  size_t _3ui(3*sizeof(unsigned int));
465  size_t _4ui(4*sizeof(unsigned int));
466 
467  if ( !_opt.is_binary() )
468  return 0;
469  else
470  {
471  size_t _3longs(3*sizeof(long));
472 
473  header += 11; // 'OFF BINARY\n'
474  header += _3longs; // #V #F #E
475  data += _be.n_vertices() * _3floats; // vertex data
476  }
477 
478  if ( _opt.vertex_has_normal() && _be.has_vertex_normals() )
479  {
480  header += 1; // N
481  data += _be.n_vertices() * _3floats;
482  }
483 
484  if ( _opt.vertex_has_color() && _be.has_vertex_colors() )
485  {
486  header += 1; // C
487  data += _be.n_vertices() * _3floats;
488  }
489 
490  if ( _opt.vertex_has_texcoord() && _be.has_vertex_texcoords() )
491  {
492  size_t _2floats(2*sizeof(float));
493  header += 2; // ST
494  data += _be.n_vertices() * _2floats;
495  }
496 
497  // topology
498  if (_be.is_triangle_mesh())
499  {
500  data += _be.n_faces() * _4ui;
501  }
502  else
503  {
504  unsigned int i, nF;
505  std::vector<VertexHandle> vhandles;
506 
507  for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
508  data += _be.get_vhandles(FaceHandle(i), vhandles) * sizeof(unsigned int);
509 
510  }
511 
512  // face colors
513  if ( _opt.face_has_color() && _be.has_face_colors() ){
514  if ( _opt.color_has_alpha() )
515  data += _be.n_faces() * _4ui;
516  else
517  data += _be.n_faces() * _3ui;
518  }
519 
520  return header+data;
521 }
522 
523 
524 //=============================================================================
525 } // namespace IO
526 } // namespace OpenMesh
527 //=============================================================================
_OFFWriter_ __OFFWriterInstance
Declare the single entity of the OFF writer.
Definition: OFFWriter.cc:71
Has (r) / store (w) texture coordinates.
Definition: Options.hh:111
size_t binary_size(BaseExporter &_be, Options _opt) const
Returns expected size of file if binary format is supported else 0.
Definition: OFFWriter.cc:458
Set binary mode for r/w.
Definition: Options.hh:105
Has (r) / store (w) vertex normals.
Definition: Options.hh:109
bool write(const std::string &, BaseExporter &, Options, std::streamsize _precision=6) const
Definition: OFFWriter.cc:86
Has (r) / store (w) face normals.
Definition: Options.hh:113
Set options for reader/writer modules.
Definition: Options.hh:95
Handle for a vertex entity.
Definition: Handles.hh:125
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:222
Handle for a face entity.
Definition: Handles.hh:146
Has (r) / store (w) face colors.
Definition: Options.hh:114
unsigned int uint32_t
Definition: SR_types.hh:90
Has (r) / store (w) vertex colors.
Definition: Options.hh:110
_IOManager_ & IOManager()
Definition: IOManager.cc:77
float float32_t
Definition: SR_types.hh:97