root/OpenSceneGraph/branches/OpenSceneGraph-2.8/src/osgPlugins/ply/vertexData.cpp @ 11274

Revision 11274, 12.3 kB (checked in by paulmartz, 4 years ago)

2.8 branch: Hm, mysteriously, the ply plugin seems to be missing changes that were previously merged. This commit brings them up to date with svn trunk as of r11237.

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   
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    int ind1 = _invertFaces ? 2 : 0;
130    int 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;
160    int     nComments;
161    char**  comments;
162   
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 ),
168                                          &nPlyElems, &elemNames,
169                                          &fileType, &version );
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    }
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 );
186   
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       
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        }
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;
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                {
253                    MESHASSERT( _colors->size() == static_cast< size_t >( nElems ) );
254                }
255
256                result = true;
257            }
258            catch( exception& e )
259            {
260                MESHERROR << "Unable to read vertex in PLY file, an exception occured:  " 
261                            << e.what() << endl;
262                // stop for loop by setting the loop variable to break condition
263                // this way resources still get released even on error cases
264                i = nPlyElems;
265               
266            }
267        }
268        // If the string is face means triangle info started
269        else if( equal_strings( elemNames[i], "face" ) )
270        try
271        {
272            // Read Triangles
273            readTriangles( file, nElems );
274            // Check whether all face elements read or not
275            MESHASSERT( _triangles->size()/3  == static_cast< size_t >( nElems ) );
276            result = true;
277        }
278        catch( exception& e )
279        {
280            MESHERROR << "Unable to read PLY file, an exception occured:  " 
281                      << e.what() << endl;
282            // stop for loop by setting the loop variable to break condition
283            // this way resources still get released even on error cases
284            i = nPlyElems;
285        }
286       
287        // free the memory that was allocated by ply_get_element_description
288        for( int j = 0; j < nProps; ++j )
289            free( props[j] );
290        free( props );
291    }
292   
293    ply_close( file );
294   
295    // free the memory that was allocated by ply_open_for_reading
296    for( int i = 0; i < nPlyElems; ++i )
297        free( elemNames[i] );
298    free( elemNames );
299
300   // If the result is true means the ply file is successfully read
301   if(result)
302   {
303        // Create geometry node
304        osg::Geometry* geom  =  new osg::Geometry;
305
306        // set the vertex array
307        geom->setVertexArray(_vertices.get());
308
309        // If the normals are not calculated calculate the normals for faces
310        if(_triangles.valid())
311        {
312            if(!_normals.valid())
313                _calculateNormals();
314
315            // set the normals
316            geom->setNormalArray(_normals.get());
317            geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
318        }
319       
320        // Add the premetive set
321        if (_triangles.valid() && _triangles->size() > 0 )
322            geom->addPrimitiveSet(_triangles.get());
323        else
324            geom->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, _vertices->size()));
325
326        // if color info is given set the color array
327        if(_colors.valid())
328        {
329            geom->setColorArray(_colors.get());
330            geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
331           
332        }
333
334       
335        // set flage true to activate the vertex buffer object of drawable
336        geom->setUseVertexBufferObjects(true);
337       
338
339        osg::Geode* geode = new osg::Geode;
340        geode->addDrawable(geom);
341        return geode;
342   }
343   
344    return NULL;
345}
346
347
348/*  Calculate the face or vertex normals of the current vertex data.  */
349void VertexData::_calculateNormals( const bool vertexNormals )
350{
351
352    if(_normals.valid())
353        return;
354
355    #ifndef NDEBUG
356    int wrongNormals = 0;
357    #endif
358
359    if(!_normals.valid())
360    {
361        _normals = new osg::Vec3Array;
362    }
363   
364    //normals.clear();
365    if( vertexNormals )
366    {
367        // initialize all normals to zero
368        for( size_t i = 0; i < _vertices->size(); ++i )
369        {
370            _normals->push_back( osg::Vec3( 0, 0, 0 ) );
371        }
372    }
373
374   
375    for( size_t i = 0; i < ((_triangles->size()));  i += 3 )
376    {
377        // iterate over all triangles and add their normals to adjacent vertices
378        Normal  triangleNormal;
379        unsigned int i0, i1, i2;
380        i0 = (*_triangles)[i+0];
381        i1 = (*_triangles)[i+1];
382        i2 = (*_triangles)[i+2];
383        triangleNormal.normal((*_vertices)[i0],
384                               (*_vertices)[i1],
385                               (*_vertices)[i2] );
386       
387        // count emtpy normals in debug mode
388        #ifndef NDEBUG
389        if( triangleNormal.triNormal.length() == 0.0f )
390            ++wrongNormals;
391        #endif
392         
393        if( vertexNormals )
394        {
395            (*_normals)[i0] += triangleNormal.triNormal;
396            (*_normals)[i1] += triangleNormal.triNormal;
397            (*_normals)[i2] += triangleNormal.triNormal;
398        }
399        else
400            _normals->push_back( triangleNormal.triNormal );
401    }
402   
403    // normalize all the normals
404    if( vertexNormals )
405        for( size_t i = 0; i < _normals->size(); ++i )
406            (*_normals)[i].normalize();
407   
408    #ifndef NDEBUG
409    if( wrongNormals > 0 )
410        MESHINFO << wrongNormals << " faces had no valid normal." << endl;
411    #endif
412}
Note: See TracBrowser for help on using the browser.