root/OpenSceneGraph/trunk/src/osgPlugins/ply/vertexData.cpp @ 13041

Revision 13041, 17.5 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1/*
2    vertexData.cpp
3    Copyright (c) 2007, Tobias Wolf <twolf@access.unizh.ch>
4    All rights reserved.
5
6    Implementation of the VertexData class.
7*/
8
9/** note, derived from Equalizer LGPL source.*/
10
11#include "typedefs.h"
12#include "vertexData.h"
13#include "ply.h"
14
15#include <cstdlib>
16#include <algorithm>
17#include <osg/Geometry>
18#include <osg/Geode>
19#include <osg/io_utils>
20
21using namespace std;
22using namespace ply;
23
24
25struct Normal{
26    osg::Vec3 triNormal;
27    void normal(osg::Vec3 v1, osg::Vec3 v2, osg::Vec3 v3)
28    {
29        osg::Vec3 u,v;
30
31        // right hand system, CCW triangle
32        u = v2 - v1;
33        v = v3 - v1;
34        triNormal = u^v;
35        triNormal.normalize();
36    }
37};
38
39/*  Contructor.  */
40VertexData::VertexData()
41    : _invertFaces( false )
42{
43    // Initialize the members
44    _vertices = NULL;
45    _colors = NULL;
46    _normals = NULL;
47    _triangles = NULL;
48    _diffuse = NULL;
49    _ambient = NULL;
50    _specular = NULL;
51}
52
53
54/*  Read the vertex and (if available/wanted) color data from the open file.  */
55void VertexData::readVertices( PlyFile* file, const int nVertices,
56                               const int fields )
57{
58    // temporary vertex structure for ply loading
59    struct _Vertex
60    {
61        float           x;
62        float           y;
63        float           z;
64        float           nx;
65        float           ny;
66        float           nz;
67        unsigned char   red;
68        unsigned char   green;
69        unsigned char   blue;
70        unsigned char   ambient_red;
71        unsigned char   ambient_green;
72        unsigned char   ambient_blue;
73        unsigned char   diffuse_red;
74        unsigned char   diffuse_green;
75        unsigned char   diffuse_blue;
76        unsigned char   specular_red;
77        unsigned char   specular_green;
78        unsigned char   specular_blue;
79        float           specular_coeff;
80        float           specular_power;
81    } vertex;
82
83    PlyProperty vertexProps[] =
84    {
85        { "x", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, x ), 0, 0, 0, 0 },
86        { "y", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, y ), 0, 0, 0, 0 },
87        { "z", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, z ), 0, 0, 0, 0 },
88        { "nx", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, nx ), 0, 0, 0, 0 },
89        { "ny", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, ny ), 0, 0, 0, 0 },
90        { "nz", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, nz ), 0, 0, 0, 0 },
91        { "red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, red ), 0, 0, 0, 0 },
92        { "green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, green ), 0, 0, 0, 0 },
93        { "blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, blue ), 0, 0, 0, 0 },
94        { "ambient_red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, ambient_red ), 0, 0, 0, 0 },
95        { "ambient_green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, ambient_green ), 0, 0, 0, 0 },
96        { "ambient_blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, ambient_blue ), 0, 0, 0, 0 },
97        { "diffuse_red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, diffuse_red ), 0, 0, 0, 0 },
98        { "diffuse_green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, diffuse_green ), 0, 0, 0, 0 },
99        { "diffuse_blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, diffuse_blue ), 0, 0, 0, 0 },
100        { "specular_red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, specular_red ), 0, 0, 0, 0 },
101        { "specular_green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, specular_green ), 0, 0, 0, 0 },
102        { "specular_blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, specular_blue ), 0, 0, 0, 0 },
103        { "specular_coeff", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, specular_coeff ), 0, 0, 0, 0 },
104        { "specular_power", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, specular_power ), 0, 0, 0, 0 },
105    };
106
107    // use all 6 properties when reading colors, only the first 3 otherwise
108    for( int i = 0; i < 3; ++i )
109        ply_get_property( file, "vertex", &vertexProps[i] );
110
111    if (fields & NORMALS)
112      for( int i = 3; i < 6; ++i )
113        ply_get_property( file, "vertex", &vertexProps[i] );
114
115    if (fields & RGB)
116      for( int i = 6; i < 9; ++i )
117        ply_get_property( file, "vertex", &vertexProps[i] );
118
119    if (fields & AMBIENT)
120      for( int i = 9; i < 12; ++i )
121        ply_get_property( file, "vertex", &vertexProps[i] );
122
123    if (fields & DIFFUSE)
124      for( int i = 12; i < 15; ++i )
125        ply_get_property( file, "vertex", &vertexProps[i] );
126
127    if (fields & SPECULAR)
128      for( int i = 15; i < 20; ++i )
129        ply_get_property( file, "vertex", &vertexProps[i] );
130
131    // check whether array is valid otherwise allocate the space
132    if(!_vertices.valid())
133        _vertices = new osg::Vec3Array;
134
135    if( fields & NORMALS )
136    {
137        if(!_normals.valid())
138            _normals = new osg::Vec3Array;
139    }
140
141    // If read colors allocate space for color array
142    if( fields & RGB )
143    {
144        if(!_colors.valid())
145            _colors = new osg::Vec4Array;
146    }
147
148    if( fields & AMBIENT )
149    {
150        if(!_ambient.valid())
151            _ambient = new osg::Vec4Array;
152    }
153
154    if( fields & DIFFUSE )
155    {
156        if(!_diffuse.valid())
157            _diffuse = new osg::Vec4Array;
158    }
159
160    if( fields & SPECULAR )
161    {
162        if(!_specular.valid())
163            _specular = new osg::Vec4Array;
164    }
165
166    // read in the vertices
167    for( int i = 0; i < nVertices; ++i )
168    {
169        ply_get_element( file, static_cast< void* >( &vertex ) );
170        _vertices->push_back( osg::Vec3( vertex.x, vertex.y, vertex.z ) );
171        if (fields & NORMALS)
172          _normals->push_back( osg::Vec3( vertex.nx, vertex.ny, vertex.nz ) );
173        if( fields & RGB )
174            _colors->push_back( osg::Vec4( (unsigned int) vertex.red / 256.0,
175                                           (unsigned int) vertex.green / 256.0 ,
176                                           (unsigned int) vertex.blue / 256.0, 0.0 ) );
177        if( fields & AMBIENT )
178          _ambient->push_back( osg::Vec4( (unsigned int) vertex.ambient_red / 256.0,
179                                           (unsigned int) vertex.ambient_green / 256.0 ,
180                                           (unsigned int) vertex.ambient_blue / 256.0, 0.0 ) );
181
182        if( fields & DIFFUSE )
183          _diffuse->push_back( osg::Vec4( (unsigned int) vertex.diffuse_red / 256.0,
184                                           (unsigned int) vertex.diffuse_green / 256.0 ,
185                                           (unsigned int) vertex.diffuse_blue / 256.0, 0.0 ) );
186
187        if( fields & SPECULAR )
188          _specular->push_back( osg::Vec4( (unsigned int) vertex.specular_red / 256.0,
189                                           (unsigned int) vertex.specular_green / 256.0 ,
190                                           (unsigned int) vertex.specular_blue / 256.0, 0.0 ) );
191    }
192}
193
194
195/*  Read the index data from the open file.  */
196void VertexData::readTriangles( PlyFile* file, const int nFaces )
197{
198    // temporary face structure for ply loading
199    struct _Face
200    {
201        unsigned char   nVertices;
202        int*            vertices;
203    } face;
204
205    PlyProperty faceProps[] =
206    {
207        { "vertex_indices", PLY_INT, PLY_INT, offsetof( _Face, vertices ),
208          1, PLY_UCHAR, PLY_UCHAR, offsetof( _Face, nVertices ) }
209    };
210
211    ply_get_property( file, "face", &faceProps[0] );
212
213    //triangles.clear();
214    //triangles.reserve( nFaces );
215    if(!_triangles.valid())
216        _triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
217
218
219    // read in the faces, asserting that they are only triangles
220    int ind1 = _invertFaces ? 2 : 0;
221    int ind3 = _invertFaces ? 0 : 2;
222    for( int i = 0; i < nFaces; ++i )
223    {
224        ply_get_element( file, static_cast< void* >( &face ) );
225        MESHASSERT( face.vertices != 0 );
226        if( (unsigned int)(face.nVertices) != 3 )
227        {
228            free( face.vertices );
229            throw MeshException( "Error reading PLY file. Encountered a "
230                                 "face which does not have three vertices." );
231        }
232        // Add the face indices in the premitive set
233        _triangles->push_back( face.vertices[ind1]);
234        _triangles->push_back( face.vertices[1]);
235        _triangles->push_back( face.vertices[ind3] );
236
237        // free the memory that was allocated by ply_get_element
238        free( face.vertices );
239    }
240}
241
242
243/*  Open a PLY file and read vertex, color and index data. and returns the node  */
244osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColors )
245{
246    int     nPlyElems;
247    char**  elemNames;
248    int     fileType;
249    float   version;
250    bool    result = false;
251    int     nComments;
252    char**  comments;
253
254    PlyFile* file = NULL;
255
256    // Try to open ply file as for reading
257    try{
258            file  = ply_open_for_reading( const_cast< char* >( filename ),
259                                          &nPlyElems, &elemNames,
260                                          &fileType, &version );
261    }
262    // Catch the if any exception thrown
263    catch( exception& e )
264    {
265        MESHERROR << "Unable to read PLY file, an exception occured:  "
266                    << e.what() << endl;
267    }
268
269    if( !file )
270    {
271        MESHERROR << "Unable to open PLY file " << filename
272                  << " for reading." << endl;
273        return NULL;
274    }
275
276    MESHASSERT( elemNames != 0 );
277
278
279    nComments = file->num_comments;
280    comments = file->comments;
281
282
283    #ifndef NDEBUG
284    MESHINFO << filename << ": " << nPlyElems << " elements, file type = "
285             << fileType << ", version = " << version << endl;
286    #endif
287
288    for( int i = 0; i < nComments; i++ )
289    {
290        if( equal_strings( comments[i], "modified by flipply" ) )
291        {
292            _invertFaces = true;
293        }
294
295    }
296    for( int i = 0; i < nPlyElems; ++i )
297    {
298        int nElems;
299        int nProps;
300
301        PlyProperty** props = NULL;
302        try{
303                props = ply_get_element_description( file, elemNames[i],
304                                                     &nElems, &nProps );
305        }
306        catch( exception& e )
307        {
308            MESHERROR << "Unable to get PLY file description, an exception occured:  "
309                        << e.what() << endl;
310        }
311        MESHASSERT( props != 0 );
312
313        #ifndef NDEBUG
314        MESHINFO << "element " << i << ": name = " << elemNames[i] << ", "
315                 << nProps << " properties, " << nElems << " elements" << endl;
316        for( int j = 0; j < nProps; ++j )
317        {
318            MESHINFO << "element " << i << ", property " << j << ": "
319                     << "name = " << props[j]->name << endl;
320        }
321        #endif
322
323        // if the string is vertex means vertex data is started
324        if( equal_strings( elemNames[i], "vertex" ) )
325        {
326            int fields = NONE;
327            // determine if the file stores vertex colors
328            for( int j = 0; j < nProps; ++j )
329              {
330                // if the string have the red means color info is there
331                if( equal_strings( props[j]->name, "x" ) )
332                    fields |= XYZ;
333                if( equal_strings( props[j]->name, "nx" ) )
334                    fields |= NORMALS;
335                if( equal_strings( props[j]->name, "red" ) )
336                    fields |= RGB;
337                if( equal_strings( props[j]->name, "ambient" ) )
338                    fields |= AMBIENT;
339                if( equal_strings( props[j]->name, "diffuse_red" ) )
340                    fields |= DIFFUSE;
341                if( equal_strings( props[j]->name, "specular_red" ) )
342                    fields |= SPECULAR;
343              }
344
345            if( ignoreColors )
346              {
347                fields &= ~(XYZ | NORMALS);
348                MESHINFO << "Colors in PLY file ignored per request." << endl;
349              }
350
351            try {
352                // Read vertices and store in a std::vector array
353                readVertices( file, nElems, fields );
354                // Check whether all vertices are loaded or not
355                MESHASSERT( _vertices->size() == static_cast< size_t >( nElems ) );
356
357                // Check if all the optional elements were read or not
358                if( fields & NORMALS )
359                {
360                    MESHASSERT( _normals->size() == static_cast< size_t >( nElems ) );
361                }
362                if( fields & RGB )
363                {
364                    MESHASSERT( _colors->size() == static_cast< size_t >( nElems ) );
365                }
366                if( fields & AMBIENT )
367                {
368                    MESHASSERT( _ambient->size() == static_cast< size_t >( nElems ) );
369                }
370                if( fields & DIFFUSE )
371                {
372                    MESHASSERT( _diffuse->size() == static_cast< size_t >( nElems ) );
373                }
374                if( fields & SPECULAR )
375                {
376                    MESHASSERT( _specular->size() == static_cast< size_t >( nElems ) );
377                }
378
379                result = true;
380            }
381            catch( exception& e )
382            {
383                MESHERROR << "Unable to read vertex in PLY file, an exception occured:  "
384                            << e.what() << endl;
385                // stop for loop by setting the loop variable to break condition
386                // this way resources still get released even on error cases
387                i = nPlyElems;
388
389            }
390        }
391        // If the string is face means triangle info started
392        else if( equal_strings( elemNames[i], "face" ) )
393        try
394        {
395            // Read Triangles
396            readTriangles( file, nElems );
397            // Check whether all face elements read or not
398            MESHASSERT( _triangles->size()/3  == static_cast< size_t >( nElems ) );
399            result = true;
400        }
401        catch( exception& e )
402        {
403            MESHERROR << "Unable to read PLY file, an exception occured:  "
404                      << e.what() << endl;
405            // stop for loop by setting the loop variable to break condition
406            // this way resources still get released even on error cases
407            i = nPlyElems;
408        }
409
410        // free the memory that was allocated by ply_get_element_description
411        for( int j = 0; j < nProps; ++j )
412            free( props[j] );
413        free( props );
414    }
415
416    ply_close( file );
417
418    // free the memory that was allocated by ply_open_for_reading
419    for( int i = 0; i < nPlyElems; ++i )
420        free( elemNames[i] );
421    free( elemNames );
422
423   // If the result is true means the ply file is successfully read
424   if(result)
425   {
426        // Create geometry node
427        osg::Geometry* geom  =  new osg::Geometry;
428
429        // set the vertex array
430        geom->setVertexArray(_vertices.get());
431
432        // If the normals are not calculated calculate the normals for faces
433        if(_triangles.valid())
434        {
435            if(!_normals.valid())
436                _calculateNormals();
437        }
438
439        // Set the normals
440        if (_normals.valid())
441        {
442            geom->setNormalArray(_normals.get());
443            geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
444        }
445
446        // Add the primitive set
447        if (_triangles.valid() && _triangles->size() > 0 )
448            geom->addPrimitiveSet(_triangles.get());
449        else
450            geom->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, _vertices->size()));
451
452
453        // Apply the colours to the model; at the moment this is a
454        // kludge because we only use one kind and apply them all the
455        // same way. Also, the priority order is completely arbitrary
456
457        if(_colors.valid())
458        {
459            geom->setColorArray(_colors.get());
460            geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
461        }
462        else if(_ambient.valid())
463        {
464            geom->setColorArray(_ambient.get());
465            geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
466        }
467        else if(_diffuse.valid())
468        {
469            geom->setColorArray(_diffuse.get());
470            geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
471        }
472        else if(_specular.valid())
473        {
474            geom->setColorArray(_specular.get());
475            geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
476        }
477
478        // set flage true to activate the vertex buffer object of drawable
479        geom->setUseVertexBufferObjects(true);
480
481
482        osg::Geode* geode = new osg::Geode;
483        geode->addDrawable(geom);
484        return geode;
485   }
486
487    return NULL;
488}
489
490
491/*  Calculate the face or vertex normals of the current vertex data.  */
492void VertexData::_calculateNormals( const bool vertexNormals )
493{
494
495    if(_normals.valid())
496        return;
497
498    #ifndef NDEBUG
499    int wrongNormals = 0;
500    #endif
501
502    if(!_normals.valid())
503    {
504        _normals = new osg::Vec3Array;
505    }
506
507    //normals.clear();
508    if( vertexNormals )
509    {
510        // initialize all normals to zero
511        for( size_t i = 0; i < _vertices->size(); ++i )
512        {
513            _normals->push_back( osg::Vec3( 0, 0, 0 ) );
514        }
515    }
516
517
518    for( size_t i = 0; i < ((_triangles->size()));  i += 3 )
519    {
520        // iterate over all triangles and add their normals to adjacent vertices
521        Normal  triangleNormal;
522        unsigned int i0, i1, i2;
523        i0 = (*_triangles)[i+0];
524        i1 = (*_triangles)[i+1];
525        i2 = (*_triangles)[i+2];
526        triangleNormal.normal((*_vertices)[i0],
527                               (*_vertices)[i1],
528                               (*_vertices)[i2] );
529
530        // count emtpy normals in debug mode
531        #ifndef NDEBUG
532        if( triangleNormal.triNormal.length() == 0.0f )
533            ++wrongNormals;
534        #endif
535
536        if( vertexNormals )
537        {
538            (*_normals)[i0] += triangleNormal.triNormal;
539            (*_normals)[i1] += triangleNormal.triNormal;
540            (*_normals)[i2] += triangleNormal.triNormal;
541        }
542        else
543            _normals->push_back( triangleNormal.triNormal );
544    }
545
546    // normalize all the normals
547    if( vertexNormals )
548        for( size_t i = 0; i < _normals->size(); ++i )
549            (*_normals)[i].normalize();
550
551    #ifndef NDEBUG
552    if( wrongNormals > 0 )
553        MESHINFO << wrongNormals << " faces had no valid normal." << endl;
554    #endif
555}
Note: See TracBrowser for help on using the browser.