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