PLYWriter.cc 22.1 KB
Newer Older
Jan Möbius's avatar
Jan Möbius committed
1
/* ========================================================================= *
Jan Möbius's avatar
Jan Möbius committed
2
3
 *                                                                           *
 *                               OpenMesh                                    *
Jan Möbius's avatar
Jan Möbius committed
4
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
Jan Möbius's avatar
Typo  
Jan Möbius committed
5
 *           Department of Computer Graphics and Multimedia                  *
Jan Möbius's avatar
Jan Möbius committed
6
7
 *                          All rights reserved.                             *
 *                            www.openmesh.org                               *
Jan Möbius's avatar
Jan Möbius committed
8
 *                                                                           *
9
 *---------------------------------------------------------------------------*
Jan Möbius's avatar
Jan Möbius committed
10
11
 * This file is part of OpenMesh.                                            *
 *---------------------------------------------------------------------------*
12
 *                                                                           *
Jan Möbius's avatar
Jan Möbius committed
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
 *                                                                           *
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
 *                                                                           *
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
 *                                                                           *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           *
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
Jan Möbius's avatar
Jan Möbius committed
39
40
 *                                                                           *
 * ========================================================================= */
41
42

/*===========================================================================*\
43
 *                                                                           *
44
45
 *   $Revision$                                                         *
 *   $Date$                   *
Jan Möbius's avatar
Jan Möbius committed
46
47
48
49
50
51
 *                                                                           *
\*===========================================================================*/


//== INCLUDES =================================================================

Matthias Möller's avatar
Matthias Möller committed
52
#include <fstream>
Jan Möbius's avatar
Jan Möbius committed
53
54
55
56
57
58
#include <OpenMesh/Core/System/config.h>
#include <OpenMesh/Core/System/omstream.hh>
#include <OpenMesh/Core/Utils/Endian.hh>
#include <OpenMesh/Core/IO/IOManager.hh>
#include <OpenMesh/Core/IO/BinaryHelper.hh>
#include <OpenMesh/Core/IO/writer/PLYWriter.hh>
59
#include <OpenMesh/Core/Utils/GenProg.hh>
Jan Möbius's avatar
Jan Möbius committed
60
61
62

#include <OpenMesh/Core/IO/SR_store.hh>

63
64
#include <iostream>

Jan Möbius's avatar
Jan Möbius committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//=== NAMESPACES ==============================================================


namespace OpenMesh {
namespace IO {


//=== INSTANCIATE =============================================================


// register the PLYLoader singleton with MeshLoader
_PLYWriter_  __PLYWriterInstance;
_PLYWriter_& PLYWriter() { return __PLYWriterInstance; }


//=== IMPLEMENTATION ==========================================================


83
84
85
86
87
88
89
90
91
92
93
94
95
96
_PLYWriter_::_PLYWriter_()
{
  IOManager().register_module(this);

  nameOfType_[Unsupported]  = "";
  nameOfType_[ValueTypeCHAR] = "char";
  nameOfType_[ValueTypeUCHAR] = nameOfType_[ValueTypeUINT8] = "uchar";
  nameOfType_[ValueTypeUSHORT] = "ushort";
  nameOfType_[ValueTypeSHORT]  = "short";
  nameOfType_[ValueTypeUINT]   = "uint";
  nameOfType_[ValueTypeINT]    = "int";
  nameOfType_[ValueTypeFLOAT32] = nameOfType_[ValueTypeFLOAT]  = "float";
  nameOfType_[ValueTypeDOUBLE] = "double";
}
Jan Möbius's avatar
Jan Möbius committed
97
98
99
100
101
102
103


//-----------------------------------------------------------------------------


bool
_PLYWriter_::
104
write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) const
Matthias Möller's avatar
Matthias Möller committed
105
106
107
108
109
110
111
112
113
114
115
116
117
118
{

  // open file
  std::ofstream out(_filename.c_str(), (_opt.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out
                                                         : std::ios_base::out) );
  return write(out, _be, _opt, _precision);
}

//-----------------------------------------------------------------------------


bool
_PLYWriter_::
write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize _precision) const
Jan Möbius's avatar
Jan Möbius committed
119
120
121
122
123
124
125
{
  // check exporter features
  if ( !check( _be, _opt ) )
    return false;


  // check writer features
126
127
128
129
130
131
132
  if ( _opt.check(Options::FaceNormal) ) {
    // Face normals are not supported
    // Uncheck these options and output message that
    // they are not written out even though they were requested
    _opt.unset(Options::FaceNormal);
    omerr() << "[PLYWriter] : Warning: Face normals are not supported and thus not exported! " << std::endl;
  }
133

134
135
136
137
138
139
140
  if ( _opt.check(Options::FaceColor) ) {
    // Face normals are not supported
    // Uncheck these options and output message that
    // they are not written out even though they were requested
    _opt.unset(Options::FaceColor);
    omerr() << "[PLYWriter] : Warning: Face colors are not supported and thus not exported! " << std::endl;
  }
Jan Möbius's avatar
Jan Möbius committed
141
142
143

  options_ = _opt;

144

145
146
147
148
149
150
151
  if (!_os.good())
  {
    omerr() << "[PLYWriter] : cannot write to stream "
    << std::endl;
    return false;
  }

152
153
  if (!_opt.check(Options::Binary))
    _os.precision(_precision);
154

155
156
157
158
159
160
161
162
  // write to file
  bool result = (_opt.check(Options::Binary) ?
     write_binary(_os, _be, _opt) :
     write_ascii(_os, _be, _opt));

  return result;
}

163
164
165
166
167
168
169
170
//-----------------------------------------------------------------------------

// helper function for casting a property
template<typename T>
const PropertyT<T>* castProperty(const BaseProperty* _prop)
{
  return dynamic_cast< const PropertyT<T>* >(_prop);
}
Jan Möbius's avatar
Jan Möbius committed
171
172

//-----------------------------------------------------------------------------
173
174
175
176
177
178
179
180
181
std::vector<_PLYWriter_::CustomProperty> _PLYWriter_::writeCustomTypeHeader(std::ostream& _out, BaseKernel::const_prop_iterator _begin, BaseKernel::const_prop_iterator _end) const
{
  std::vector<CustomProperty> customProps;
  for (;_begin != _end; ++_begin)
  {
    BaseProperty* prop = *_begin;


    // check, if property is persistant
182
    if (!prop || !prop->persistent())
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
      continue;


    // identify type of property
    CustomProperty cProp(prop);
    size_t propSize = prop->element_size();
    switch (propSize)
    {
    case 1:
    {
      assert_compile(sizeof(char) == 1);
      //check, if prop is a char or unsigned char by dynamic_cast
      //char, unsigned char and signed char are 3 distinct types
      if (castProperty<signed char>(prop) != 0 || castProperty<char>(prop) != 0) //treat char as signed char
        cProp.type = ValueTypeCHAR;
      else if (castProperty<unsigned char>(prop) != 0)
        cProp.type = ValueTypeUCHAR;
      break;
    }
    case 2:
    {
      assert_compile (sizeof(short) == 2);
      if (castProperty<signed short>(prop) != 0)
        cProp.type = ValueTypeSHORT;
      else if (castProperty<unsigned short>(prop) != 0)
        cProp.type = ValueTypeUSHORT;
      break;
    }
    case 4:
    {
      assert_compile (sizeof(int) == 4);
      assert_compile (sizeof(float) == 4);
      if (castProperty<signed int>(prop) != 0)
        cProp.type = ValueTypeINT;
      else if (castProperty<unsigned int>(prop) != 0)
        cProp.type = ValueTypeUINT;
      else if (castProperty<float>(prop) != 0)
        cProp.type = ValueTypeFLOAT;
      break;
Jan Möbius's avatar
Jan Möbius committed
222

223
224
225
226
227
228
229
230
231
    }
    case 8:
      assert_compile (sizeof(double) == 8);
      if (castProperty<double>(prop) != 0)
        cProp.type = ValueTypeDOUBLE;
      break;
    default:
      break;
    }
Jan Möbius's avatar
Jan Möbius committed
232

233
234
235
236
237
238
239
240
241
242
243
244
    if (cProp.type != Unsupported)
    {
      // property type was identified and it is persistant, write into header
      customProps.push_back(cProp);
      _out << "property " << nameOfType_[cProp.type] << " " << cProp.property->name() << "\n";
    }
  }
  return customProps;
}

//-----------------------------------------------------------------------------

245
246
template<bool binary>
void _PLYWriter_::write_customProp(std::ostream& _out, const CustomProperty& _prop, size_t _index) const
247
248
{
  if (_prop.type == ValueTypeCHAR)
249
    writeProxy(_prop.type,_out, castProperty<signed char>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
250
  else if (_prop.type == ValueTypeUCHAR || _prop.type == ValueTypeUINT8)
251
    writeProxy(_prop.type,_out, castProperty<unsigned char>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
252
  else if (_prop.type == ValueTypeSHORT)
253
    writeProxy(_prop.type,_out, castProperty<signed short>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
254
  else if (_prop.type == ValueTypeUSHORT)
255
    writeProxy(_prop.type,_out, castProperty<unsigned short>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
256
  else if (_prop.type == ValueTypeUINT)
257
    writeProxy(_prop.type,_out, castProperty<unsigned int>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
258
  else if (_prop.type == ValueTypeINT || _prop.type == ValueTypeINT32)
259
    writeProxy(_prop.type,_out, castProperty<signed int>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
260
  else if (_prop.type == ValueTypeFLOAT || _prop.type == ValueTypeFLOAT32)
261
    writeProxy(_prop.type,_out, castProperty<float>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
262
  else if (_prop.type == ValueTypeDOUBLE)
263
    writeProxy(_prop.type,_out, castProperty<double>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
264
265
266
267
268
269
270
271
}


//-----------------------------------------------------------------------------



void _PLYWriter_::write_header(std::ostream& _out, BaseExporter& _be, Options& _opt, std::vector<CustomProperty>& _ovProps, std::vector<CustomProperty>& _ofProps) const {
Jan Möbius's avatar
Jan Möbius committed
272
  //writing header
273
  _out << "ply" << '\n';
274
275
276
277
278
279
280

  if (_opt.is_binary()) {
    _out << "format ";
    if ( options_.check(Options::MSB) )
      _out << "binary_big_endian ";
    else
      _out << "binary_little_endian ";
281
    _out << "1.0" << '\n';
282
  } else
283
    _out << "format ascii 1.0" << '\n';
284

285
  _out << "element vertex " << _be.n_vertices() << '\n';
Jan Möbius's avatar
Jan Möbius committed
286

287
288
289
  _out << "property float x" << '\n';
  _out << "property float y" << '\n';
  _out << "property float z" << '\n';
Jan Möbius's avatar
Jan Möbius committed
290

291
  if ( _opt.vertex_has_normal() ){
292
293
294
    _out << "property float nx" << '\n';
    _out << "property float ny" << '\n';
    _out << "property float nz" << '\n';
295
296
  }

297
  if ( _opt.vertex_has_texcoord() ){
298
299
    _out << "property float u" << '\n';
    _out << "property float v" << '\n';
300
301
  }

Jan Möbius's avatar
Jan Möbius committed
302
  if ( _opt.vertex_has_color() ){
303
    if ( _opt.color_is_float() ) {
304
305
306
      _out << "property float red" << '\n';
      _out << "property float green" << '\n';
      _out << "property float blue" << '\n';
307
308

      if ( _opt.color_has_alpha() )
309
        _out << "property float alpha" << '\n';
310
    } else {
311
312
313
      _out << "property uchar red" << '\n';
      _out << "property uchar green" << '\n';
      _out << "property uchar blue" << '\n';
314
315

      if ( _opt.color_has_alpha() )
316
        _out << "property uchar alpha" << '\n';
317
    }
Jan Möbius's avatar
Jan Möbius committed
318
319
  }

320
  _ovProps = writeCustomTypeHeader(_out, _be.kernel()->vprops_begin(), _be.kernel()->vprops_end());
321

322
323
  _out << "element face " << _be.n_faces() << '\n';
  _out << "property list uchar int vertex_indices" << '\n';
324

325
  _ofProps = writeCustomTypeHeader(_out, _be.kernel()->fprops_begin(), _be.kernel()->fprops_end());
326

327
  _out << "end_header" << '\n';
328
329
330
331
332
333
334
335
336
337
}


//-----------------------------------------------------------------------------


bool
_PLYWriter_::
write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const
{
Jan Möbius's avatar
Jan Möbius committed
338
  
Jan Möbius's avatar
Jan Möbius committed
339
  unsigned int i, nV, nF;
340
341
342
343
344
345
346
347
348
  Vec3f v, n;
  OpenMesh::Vec3ui c;
  OpenMesh::Vec4ui cA;
  OpenMesh::Vec3f cf;
  OpenMesh::Vec4f cAf;
  OpenMesh::Vec2f t;
  VertexHandle vh;
  std::vector<VertexHandle> vhandles;

349
350
351
352
  std::vector<CustomProperty> vProps;
  std::vector<CustomProperty> fProps;

  write_header(_out, _be, _opt, vProps, fProps);
Jan Möbius's avatar
Jan Möbius committed
353

354
355
356
  if (_opt.color_is_float())
    _out << std::fixed;

Jan Möbius's avatar
Jan Möbius committed
357
  // vertex data (point, normals, colors, texcoords)
358
  for (i=0, nV=int(_be.n_vertices()); i<nV; ++i)
Jan Möbius's avatar
Jan Möbius committed
359
360
361
362
363
364
365
  {
    vh = VertexHandle(i);
    v  = _be.point(vh);

    //Vertex
    _out << v[0] << " " << v[1] << " " << v[2];

366
367
368
369
370
371
    // Vertex Normals
    if ( _opt.vertex_has_normal() ){
      n = _be.normal(vh);
      _out << " " << n[0] << " " << n[1] << " " << n[2];
    }

372
373
374
375
376
377
    // Vertex TexCoords
    if ( _opt.vertex_has_texcoord() ) {
    	t = _be.texcoord(vh);
    	_out << " " << t[0] << " " << t[1];
    }

Jan Möbius's avatar
Jan Möbius committed
378
379
380
381
    // VertexColor
    if ( _opt.vertex_has_color() ) {
      //with alpha
      if ( _opt.color_has_alpha() ){
382
383
384
385
386
387
388
        if (_opt.color_is_float()) {
          cAf = _be.colorAf(vh);
          _out << " " << cAf;
        } else {
          cA  = _be.colorAi(vh);
          _out << " " << cA;
        }
Jan Möbius's avatar
Jan Möbius committed
389
390
      }else{
        //without alpha
391
392
393
394
395
396
397
        if (_opt.color_is_float()) {
          cf = _be.colorf(vh);
          _out << " " << cf;
        } else {
          c  = _be.colori(vh);
          _out << " " << c;
        }
Jan Möbius's avatar
Jan Möbius committed
398
399
400
      }
    }

401
402
403

    // write custom properties for vertices
    for (std::vector<CustomProperty>::iterator iter = vProps.begin(); iter < vProps.end(); ++iter)
404
      write_customProp<false>(_out,*iter,i);
405

Jan Möbius's avatar
Jan Möbius committed
406
407
    _out << "\n";
  }
408

Jan Möbius's avatar
Jan Möbius committed
409
  // faces (indices starting at 0)
410
  for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
Jan Möbius's avatar
Jan Möbius committed
411
  {
412
413
414
415
416
417
418
419
    // write vertex indices per face
    nV = _be.get_vhandles(FaceHandle(i), vhandles);
    _out << nV;
    for (size_t j=0; j<vhandles.size(); ++j)
      _out << " " << vhandles[j].idx();

    // write custom props
    for (std::vector<CustomProperty>::iterator iter = fProps.begin(); iter < fProps.end(); ++iter)
420
      write_customProp<false>(_out,*iter,i);
421
    _out << "\n";
Jan Möbius's avatar
Jan Möbius committed
422
423
424
425
426
427
428
429
430
  }


  return true;
}


//-----------------------------------------------------------------------------

431
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, int value) const {
Jan Möbius's avatar
Jan Möbius committed
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452

  uint32_t tmp32;
  uint8_t tmp8;

  switch (_type) {
    case ValueTypeINT:
    case ValueTypeINT32:
      tmp32 = value;
      store(_out, tmp32, options_.check(Options::MSB) );
      break;
//     case ValueTypeUINT8:
default :
      tmp8 = value;
      store(_out, tmp8, options_.check(Options::MSB) );
      break;
//     default :
//       std::cerr << "unsupported conversion type to int: " << _type << std::endl;
//       break;
  }
}

453
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned int value) const {
Jan Möbius's avatar
Jan Möbius committed
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474

  uint32_t tmp32;
  uint8_t tmp8;

  switch (_type) {
    case ValueTypeINT:
    case ValueTypeINT32:
      tmp32 = value;
      store(_out, tmp32, options_.check(Options::MSB) );
      break;
//     case ValueTypeUINT8:
default :
      tmp8 = value;
      store(_out, tmp8, options_.check(Options::MSB) );
      break;
//     default :
//       std::cerr << "unsupported conversion type to int: " << _type << std::endl;
//       break;
  }
}

475
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, float value) const {
Jan Möbius's avatar
Jan Möbius committed
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490

  float32_t tmp;

  switch (_type) {
    case ValueTypeFLOAT32:
    case ValueTypeFLOAT:
      tmp = value;
      store( _out , tmp, options_.check(Options::MSB) );
      break;
    default :
      std::cerr << "unsupported conversion type to float: " << _type << std::endl;
      break;
  }
}

491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, double value) const {

  double_t tmp;

  switch (_type) {
    case ValueTypeDOUBLE:
      tmp = value;
      store( _out , tmp, options_.check(Options::MSB) );
      break;
    default :
      std::cerr << "unsupported conversion type to float: " << _type << std::endl;
      break;
  }
}

void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, signed char value) const{

  int8_t tmp;

  switch (_type) {
  case ValueTypeCHAR:
    tmp = value;
    store(_out, tmp, options_.check(Options::MSB) );
    break;
  default :
    std::cerr << "unsupported conversion type to int: " << _type << std::endl;
    break;
  }
}
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned char value) const{

  uint8_t tmp;

  switch (_type) {
  case ValueTypeUCHAR:
    tmp = value;
    store(_out, tmp, options_.check(Options::MSB) );
    break;
  default :
    std::cerr << "unsupported conversion type to int: " << _type << std::endl;
    break;
  }
}
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, short value) const{

  int16_t tmp;

  switch (_type) {
  case ValueTypeSHORT:
    tmp = value;
    store(_out, tmp, options_.check(Options::MSB) );
    break;
  default :
    std::cerr << "unsupported conversion type to int: " << _type << std::endl;
    break;
  }
}
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned short value) const{

  uint16_t tmp;

  switch (_type) {
  case ValueTypeUSHORT:
    tmp = value;
    store(_out, tmp, options_.check(Options::MSB) );
    break;
  default :
    std::cerr << "unsupported conversion type to int: " << _type << std::endl;
    break;
  }
}

563
bool
Jan Möbius's avatar
Jan Möbius committed
564
_PLYWriter_::
565
write_binary(std::ostream& _out, BaseExporter& _be, Options _opt) const
Jan Möbius's avatar
Jan Möbius committed
566
{
Jan Möbius's avatar
Jan Möbius committed
567
  
Jan Möbius's avatar
Jan Möbius committed
568
  unsigned int i, nV, nF;
Jan Möbius's avatar
Jan Möbius committed
569
570
  Vec3f v, n;
  Vec2f t;
571
  OpenMesh::Vec4uc c;
572
  OpenMesh::Vec4f cf;
Jan Möbius's avatar
Jan Möbius committed
573
574
575
  VertexHandle vh;
  std::vector<VertexHandle> vhandles;

576
577
578
579
580
  // vProps and fProps will be empty, until custom properties are supported by the binary writer
  std::vector<CustomProperty> vProps;
  std::vector<CustomProperty> fProps;

  write_header(_out, _be, _opt, vProps, fProps);
581

Jan Möbius's avatar
Jan Möbius committed
582
  // vertex data (point, normals, texcoords)
583
  for (i=0, nV=int(_be.n_vertices()); i<nV; ++i)
Jan Möbius's avatar
Jan Möbius committed
584
585
586
  {
    vh = VertexHandle(i);
    v  = _be.point(vh);
587

Jan Möbius's avatar
Jan Möbius committed
588
589
590
591
    //vertex
    writeValue(ValueTypeFLOAT, _out, v[0]);
    writeValue(ValueTypeFLOAT, _out, v[1]);
    writeValue(ValueTypeFLOAT, _out, v[2]);
592

593
594
595
596
597
598
599
600
    // Vertex Normal
    if ( _opt.vertex_has_normal() ){
      n = _be.normal(vh);
      writeValue(ValueTypeFLOAT, _out, n[0]);
      writeValue(ValueTypeFLOAT, _out, n[1]);
      writeValue(ValueTypeFLOAT, _out, n[2]);
    }

601
602
603
604
605
606
607
    // Vertex TexCoords
    if ( _opt.vertex_has_texcoord() ) {
    	t = _be.texcoord(vh);
    	writeValue(ValueTypeFLOAT, _out, t[0]);
    	writeValue(ValueTypeFLOAT, _out, t[1]);
    }

Jan Möbius's avatar
Jan Möbius committed
608
609
    // vertex color
    if ( _opt.vertex_has_color() ) {
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
        if ( _opt.color_is_float() ) {
          cf  = _be.colorAf(vh);
          writeValue(ValueTypeFLOAT, _out, cf[0]);
          writeValue(ValueTypeFLOAT, _out, cf[1]);
          writeValue(ValueTypeFLOAT, _out, cf[2]);

          if ( _opt.color_has_alpha() )
            writeValue(ValueTypeFLOAT, _out, cf[3]);
        } else {
          c  = _be.colorA(vh);
          writeValue(ValueTypeUCHAR, _out, (int)c[0]);
          writeValue(ValueTypeUCHAR, _out, (int)c[1]);
          writeValue(ValueTypeUCHAR, _out, (int)c[2]);

          if ( _opt.color_has_alpha() )
            writeValue(ValueTypeUCHAR, _out, (int)c[3]);
        }
Jan Möbius's avatar
Jan Möbius committed
627
628
    }

629
630
    for (std::vector<CustomProperty>::iterator iter = vProps.begin(); iter < vProps.end(); ++iter)
      write_customProp<true>(_out,*iter,i);
Jan Möbius's avatar
Jan Möbius committed
631
  }
632
633
634


  for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
Jan Möbius's avatar
Jan Möbius committed
635
  {
636
637
638
639
640
641
642
643
    //face
    nV = _be.get_vhandles(FaceHandle(i), vhandles);
    writeValue(ValueTypeUINT8, _out, nV);
    for (size_t j=0; j<vhandles.size(); ++j)
      writeValue(ValueTypeINT32, _out, vhandles[j].idx() );

    for (std::vector<CustomProperty>::iterator iter = fProps.begin(); iter < fProps.end(); ++iter)
      write_customProp<true>(_out,*iter,i);
Jan Möbius's avatar
Jan Möbius committed
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
  }

  return true;
}

// ----------------------------------------------------------------------------


size_t
_PLYWriter_::
binary_size(BaseExporter& _be, Options _opt) const
{
  size_t header(0);
  size_t data(0);
  size_t _3floats(3*sizeof(float));
  size_t _3ui(3*sizeof(unsigned int));
  size_t _4ui(4*sizeof(unsigned int));
661

Jan Möbius's avatar
Jan Möbius committed
662
663
664
665
  if ( !_opt.is_binary() )
    return 0;
  else
  {
Jan Möbius's avatar
Jan Möbius committed
666
667
668

    size_t _3longs(3*sizeof(long));

Jan Möbius's avatar
Jan Möbius committed
669
670
671
672
673
674
675
676
677
678
    header += 11;                             // 'OFF BINARY\n'
    header += _3longs;                        // #V #F #E
    data   += _be.n_vertices() * _3floats;    // vertex data
  }

  if ( _opt.vertex_has_normal() && _be.has_vertex_normals() )
  {
    header += 1; // N
    data   += _be.n_vertices() * _3floats;
  }
679

Jan Möbius's avatar
Jan Möbius committed
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
  if ( _opt.vertex_has_color() && _be.has_vertex_colors() )
  {
    header += 1; // C
    data   += _be.n_vertices() * _3floats;
  }

  if ( _opt.vertex_has_texcoord() && _be.has_vertex_texcoords() )
  {
    size_t _2floats(2*sizeof(float));
    header += 2; // ST
    data   += _be.n_vertices() * _2floats;
  }

  // topology
  if (_be.is_triangle_mesh())
  {
    data += _be.n_faces() * _4ui;
  }
  else
  {
Jan Möbius's avatar
Jan Möbius committed
700
    unsigned int i, nF;
Jan Möbius's avatar
Jan Möbius committed
701
702
    std::vector<VertexHandle> vhandles;

703
    for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
Jan Möbius's avatar
Jan Möbius committed
704
    {
Jan Möbius's avatar
Jan Möbius committed
705
      data += _be.get_vhandles(FaceHandle(i), vhandles) * sizeof(unsigned int);
Jan Möbius's avatar
Jan Möbius committed
706
707
708

    }
  }
709

Jan Möbius's avatar
Jan Möbius committed
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
  // face colors
  if ( _opt.face_has_color() && _be.has_face_colors() ){
    if ( _opt.color_has_alpha() )
      data += _be.n_faces() * _4ui;
    else
      data += _be.n_faces() * _3ui;
  }

  return header+data;
}


//=============================================================================
} // namespace IO
} // namespace OpenMesh
//=============================================================================