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

Revision 10040, 12.0 kB (checked in by robert, 6 years ago)

From Santosh Gaikwad, "I have added the exception handling in ply loader. All exceptions I am catching in VertexData::readPlyFile() and made sure that application will not crash or exit if any exception occurred. I am returning NULL from VertexData::readPlyFile() if any exception occurred.
"

RevLine 
[10012]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
13#include "vertexData.h"
14#include "ply.h"
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   
49}
50
51
52/*  Read the vertex and (if available/wanted) color data from the open file.  */
53void VertexData::readVertices( PlyFile* file, const int nVertices,
54                               const bool readColors )
55{
56    // temporary vertex structure for ply loading
57    struct _Vertex
58    {
59        float           x;
60        float           y;
61        float           z;
62        unsigned char   r;
63        unsigned char   g;
64        unsigned char   b;
65    } vertex;
66
67    PlyProperty vertexProps[] =
68    {
69        { "x", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, x ), 0, 0, 0, 0 },
70        { "y", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, y ), 0, 0, 0, 0 },
71        { "z", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, z ), 0, 0, 0, 0 },
72        { "red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, r ), 0, 0, 0, 0 },
73        { "green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, g ), 0, 0, 0, 0 },
74        { "blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, b ), 0, 0, 0, 0 }
75    };
76   
77    // use all 6 properties when reading colors, only the first 3 otherwise
78    int limit = readColors ? 6 : 3;
79    for( int i = 0; i < limit; ++i )
80        ply_get_property( file, "vertex", &vertexProps[i] );
81   
82    // check whether array is valid otherwise allocate the space
83    if(!_vertices.valid())
84        _vertices = new osg::Vec3Array;
85   
86    // If read colors allocate space for color array
87    if( readColors )
88    {
89        if(!_colors.valid())
90            _colors = new osg::Vec4Array;
91    }
92   
93    // read in the vertices
94    for( int i = 0; i < nVertices; ++i )
95    {
96        ply_get_element( file, static_cast< void* >( &vertex ) );
97        _vertices->push_back( osg::Vec3( vertex.x, vertex.y, vertex.z ) );
98        if( readColors )
99            _colors->push_back( osg::Vec4( (unsigned int) vertex.r / 256.0, (unsigned int) vertex.g / 256.0 , (unsigned int) vertex.b/ 256.0, 0.0 ) );
100    }
101}
102
103
104/*  Read the index data from the open file.  */
105void VertexData::readTriangles( PlyFile* file, const int nFaces )
106{
107    // temporary face structure for ply loading
108    struct _Face
109    {
110        unsigned char   nVertices;
111        int*            vertices;
112    } face;
113
114    PlyProperty faceProps[] =
115    {
116        { "vertex_indices", PLY_INT, PLY_INT, offsetof( _Face, vertices ),
117          1, PLY_UCHAR, PLY_UCHAR, offsetof( _Face, nVertices ) }
118    };
119   
120    ply_get_property( file, "face", &faceProps[0] );
121   
122    //triangles.clear();
123    //triangles.reserve( nFaces );
124    if(!_triangles.valid())
125        _triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
126
127   
128    // read in the faces, asserting that they are only triangles
129    uint8_t ind1 = _invertFaces ? 2 : 0;
130    uint8_t ind3 = _invertFaces ? 0 : 2;
131    for( int i = 0; i < nFaces; ++i )
132    {
133        ply_get_element( file, static_cast< void* >( &face ) );
134        MESHASSERT( face.vertices != 0 );
135        if( (unsigned int)(face.nVertices) != 3 )
136        {
137            free( face.vertices );
138            throw MeshException( "Error reading PLY file. Encountered a "
139                                 "face which does not have three vertices." );
140        }
141        // Add the face indices in the premitive set
142        _triangles->push_back( face.vertices[ind1]);
143        _triangles->push_back( face.vertices[1]);
144        _triangles->push_back( face.vertices[ind3] );
145       
146        // free the memory that was allocated by ply_get_element
147        free( face.vertices );
148    }
149}
150
151
152/*  Open a PLY file and read vertex, color and index data. and returns the node  */
153osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColors )
154{
155    int     nPlyElems;
156    char**  elemNames;
157    int     fileType;
158    float   version;
159    bool    result = false;
[10040]160    int     nComments;
161    char**  comments;
[10012]162   
[10040]163    PlyFile* file = NULL;
164
165    // Try to open ply file as for reading
166    try{
167            file  = ply_open_for_reading( const_cast< char* >( filename ),
[10012]168                                          &nPlyElems, &elemNames,
169                                          &fileType, &version );
[10040]170    }
171    // Catch the if any exception thrown
172    catch( exception& e )
173    {
174        MESHERROR << "Unable to read PLY file, an exception occured:  " 
175                    << e.what() << endl;
176    }
[10012]177
178    if( !file )
179    {
180        MESHERROR << "Unable to open PLY file " << filename
181                  << " for reading." << endl;
182        return NULL;
183    }
184
185    MESHASSERT( elemNames != 0 );
[10040]186   
[10012]187
188    nComments = file->num_comments;
189    comments = file->comments;
190   
191   
192    #ifndef NDEBUG
193    MESHINFO << filename << ": " << nPlyElems << " elements, file type = " 
194             << fileType << ", version = " << version << endl;
195    #endif
196
197    for( int i = 0; i < nComments; i++ )
198    {
199        if( equal_strings( comments[i], "modified by flipply" ) )
200        {
201            _invertFaces = true;
202        }
203
204    }
205    for( int i = 0; i < nPlyElems; ++i )
206    {
207        int nElems;
208        int nProps;
209       
[10040]210        PlyProperty** props = NULL;
211        try{
212                props = ply_get_element_description( file, elemNames[i],
213                                                     &nElems, &nProps );
214        }
215        catch( exception& e )
216        {
217            MESHERROR << "Unable to get PLY file description, an exception occured:  " 
218                        << e.what() << endl;
219        }
[10012]220        MESHASSERT( props != 0 );
221       
222        #ifndef NDEBUG
223        MESHINFO << "element " << i << ": name = " << elemNames[i] << ", "
224                 << nProps << " properties, " << nElems << " elements" << endl;
225        for( int j = 0; j < nProps; ++j )
226        {
227            MESHINFO << "element " << i << ", property " << j << ": "
228                     << "name = " << props[j]->name << endl;
229        }
230        #endif
231       
232        // if the string is vertex means vertex data is started
233        if( equal_strings( elemNames[i], "vertex" ) )
234        {
235            bool hasColors = false;
236            // determine if the file stores vertex colors
237            for( int j = 0; j < nProps; ++j )
238                // if the string have the red means color info is there
239                if( equal_strings( props[j]->name, "red" ) )
240                    hasColors = true;
241           
242            if( ignoreColors )
243                MESHINFO << "Colors in PLY file ignored per request." << endl;
[10040]244         
245            try {   
246                // Read vertices and store in a std::vector array
247                readVertices( file, nElems, hasColors && !ignoreColors );
248                // Check whether all vertices are loaded or not
249                MESHASSERT( _vertices->size() == static_cast< size_t >( nElems ) );
250                // Check all color elements read or not
251                if( hasColors && !ignoreColors )
252                    MESHASSERT( _colors->size() == static_cast< size_t >( nElems ) );
253            }
254            catch( exception& e )
255            {
256                MESHERROR << "Unable to read vertex in PLY file, an exception occured:  " 
257                            << e.what() << endl;
258                // stop for loop by setting the loop variable to break condition
259                // this way resources still get released even on error cases
260                i = nPlyElems;
261               
262            }
[10012]263        }
264        // If the string is face means triangle info started
265        else if( equal_strings( elemNames[i], "face" ) )
266        try
267        {
268            // Read Triangles
269            readTriangles( file, nElems );
270            // Check whether all face elements read or not
271            MESHASSERT( _triangles->size()/3  == static_cast< size_t >( nElems ) );
272            result = true;
273        }
274        catch( exception& e )
275        {
276            MESHERROR << "Unable to read PLY file, an exception occured:  " 
277                      << e.what() << endl;
278            // stop for loop by setting the loop variable to break condition
279            // this way resources still get released even on error cases
280            i = nPlyElems;
281        }
282       
283        // free the memory that was allocated by ply_get_element_description
284        for( int j = 0; j < nProps; ++j )
285            free( props[j] );
286        free( props );
287    }
288   
289    ply_close( file );
290   
291    // free the memory that was allocated by ply_open_for_reading
292    for( int i = 0; i < nPlyElems; ++i )
293        free( elemNames[i] );
294    free( elemNames );
295
296   // If the result is true means the ply file is successfully read
297   if(result)
298   {
299        // Create geometry node
300        osg::Geometry* geom  =  new osg::Geometry;
301
302        // set the vertex array
303        geom->setVertexArray(_vertices.get());
304
305        // If the normals are not calculated calculate the normals for faces
306        if(!_normals.valid())
307            _calculateNormals();
308
309       
310        // set the normals
311        geom->setNormalArray(_normals.get());
312        geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
313       
314        // Add the premetive set
315        geom->addPrimitiveSet(_triangles.get());
316
317        // if color info is given set the color array
318        if(_colors.valid())
319        {
320            geom->setColorArray(_colors.get());
321            geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
322           
323        }
324
325       
326        // set flage true to activate the vertex buffer object of drawable
327        geom->setUseVertexBufferObjects(true);
328       
329
330        osg::Geode* geode = new osg::Geode;
331        geode->addDrawable(geom);
332        return geode;
333   }
334   
335    return NULL;
336}
337
338
339/*  Calculate the face or vertex normals of the current vertex data.  */
340void VertexData::_calculateNormals( const bool vertexNormals )
341{
342
343    if(_normals.valid())
344        return;
345
346    #ifndef NDEBUG
347    int wrongNormals = 0;
348    #endif
349
350    if(!_normals.valid())
351    {
352        _normals = new osg::Vec3Array;
353    }
354   
355    //normals.clear();
356    if( vertexNormals )
357    {
358        // initialize all normals to zero
359        for( size_t i = 0; i < _vertices->size(); ++i )
360        {
361            _normals->push_back( osg::Vec3( 0, 0, 0 ) );
362        }
363    }
364
365   
366    for( size_t i = 0; i < ((_triangles->size()));  i += 3 )
367    {
368        // iterate over all triangles and add their normals to adjacent vertices
369        Normal  triangleNormal;
370        unsigned int i0, i1, i2;
371        i0 = (*_triangles)[i+0];
372        i1 = (*_triangles)[i+1];
373        i2 = (*_triangles)[i+2];
374        triangleNormal.normal((*_vertices)[i0],
375                               (*_vertices)[i1],
376                               (*_vertices)[i2] );
377       
378        // count emtpy normals in debug mode
379        #ifndef NDEBUG
380        if( triangleNormal.triNormal.length() == 0.0f )
381            ++wrongNormals;
382        #endif
383         
384        if( vertexNormals )
385        {
386            (*_normals)[i0] += triangleNormal.triNormal;
387            (*_normals)[i1] += triangleNormal.triNormal;
388            (*_normals)[i2] += triangleNormal.triNormal;
389        }
390        else
391            _normals->push_back( triangleNormal.triNormal );
392    }
393   
394    // normalize all the normals
395    if( vertexNormals )
396        for( size_t i = 0; i < _normals->size(); ++i )
397            (*_normals)[i].normalize();
398   
399    #ifndef NDEBUG
400    if( wrongNormals > 0 )
401        MESHINFO << wrongNormals << " faces had no valid normal." << endl;
402    #endif
403}
Note: See TracBrowser for help on using the browser.