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

Revision 10012, 11.1 kB (checked in by robert, 6 years ago)

From Santosh Gaikwad, ply plugin, based on Equalizer and other LGPL compatible sources.

"Attached is the osg-plugin for reading ply ( Stanford Triangle Format ) file. I have written the plugin according to OSG standard and have also added cmake build system. The plugin is working fine on both Linux and Windows and should behave similarly on other OS as well."

"I developed this plugin while working on a project based on Equalizer. So VertexData? which I am using is taken from equalizer and modified to make them work as separate OSG plugin.
Before contributing this plugin to OSG community, I asked project manager of Equalizer project Stefen regarding potential licensing issues and this is what he has said

"The kd-Tree (VertexBuffer?*) is LGPL-licensed, and the base ply loader (ply*) is BSD. As long as you leave the copyright notices intact, there is no issue."

so I think using these files in OSG should not be a problem.

As far as author of ReaderWriterPLY.cpp is concerned I am the author. I am working for Darshan3d which is a subsidiary of VizExperts? thats why I have put VizExperts? copyright."

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;
160    int        nComments;
161    char**    comments;
162   
163    PlyFile* file = ply_open_for_reading( const_cast< char* >( filename ),
164                                          &nPlyElems, &elemNames,
165                                          &fileType, &version );
166
167    if( !file )
168    {
169        MESHERROR << "Unable to open PLY file " << filename
170                  << " for reading." << endl;
171        return NULL;
172    }
173
174    MESHASSERT( elemNames != 0 );
175
176    nComments = file->num_comments;
177    comments = file->comments;
178   
179   
180    #ifndef NDEBUG
181    MESHINFO << filename << ": " << nPlyElems << " elements, file type = " 
182             << fileType << ", version = " << version << endl;
183    #endif
184
185    for( int i = 0; i < nComments; i++ )
186    {
187        if( equal_strings( comments[i], "modified by flipply" ) )
188        {
189            _invertFaces = true;
190        }
191
192    }
193    for( int i = 0; i < nPlyElems; ++i )
194    {
195        int nElems;
196        int nProps;
197       
198        PlyProperty** props = ply_get_element_description( file, elemNames[i],
199                                                           &nElems, &nProps );
200        MESHASSERT( props != 0 );
201       
202        #ifndef NDEBUG
203        MESHINFO << "element " << i << ": name = " << elemNames[i] << ", "
204                 << nProps << " properties, " << nElems << " elements" << endl;
205        for( int j = 0; j < nProps; ++j )
206        {
207            MESHINFO << "element " << i << ", property " << j << ": "
208                     << "name = " << props[j]->name << endl;
209        }
210        #endif
211       
212        // if the string is vertex means vertex data is started
213        if( equal_strings( elemNames[i], "vertex" ) )
214        {
215            bool hasColors = false;
216            // determine if the file stores vertex colors
217            for( int j = 0; j < nProps; ++j )
218                // if the string have the red means color info is there
219                if( equal_strings( props[j]->name, "red" ) )
220                    hasColors = true;
221           
222            if( ignoreColors )
223                MESHINFO << "Colors in PLY file ignored per request." << endl;
224           
225            // Read vertices and store in a std::vector array
226            readVertices( file, nElems, hasColors && !ignoreColors );
227            // Check whether all vertices are loaded or not
228            MESHASSERT( _vertices->size() == static_cast< size_t >( nElems ) );
229            // Check all color elements read or not
230            if( hasColors && !ignoreColors )
231                MESHASSERT( _colors->size() == static_cast< size_t >( nElems ) );
232        }
233        // If the string is face means triangle info started
234        else if( equal_strings( elemNames[i], "face" ) )
235        try
236        {
237            // Read Triangles
238            readTriangles( file, nElems );
239            // Check whether all face elements read or not
240            MESHASSERT( _triangles->size()/3  == static_cast< size_t >( nElems ) );
241            result = true;
242        }
243        catch( exception& e )
244        {
245            MESHERROR << "Unable to read PLY file, an exception occured:  " 
246                      << e.what() << endl;
247            // stop for loop by setting the loop variable to break condition
248            // this way resources still get released even on error cases
249            i = nPlyElems;
250        }
251       
252        // free the memory that was allocated by ply_get_element_description
253        for( int j = 0; j < nProps; ++j )
254            free( props[j] );
255        free( props );
256    }
257   
258    ply_close( file );
259   
260    // free the memory that was allocated by ply_open_for_reading
261    for( int i = 0; i < nPlyElems; ++i )
262        free( elemNames[i] );
263    free( elemNames );
264
265   // If the result is true means the ply file is successfully read
266   if(result)
267   {
268        // Create geometry node
269        osg::Geometry* geom  =  new osg::Geometry;
270
271        // set the vertex array
272        geom->setVertexArray(_vertices.get());
273
274        // If the normals are not calculated calculate the normals for faces
275        if(!_normals.valid())
276            _calculateNormals();
277
278       
279        // set the normals
280        geom->setNormalArray(_normals.get());
281        geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
282       
283        // Add the premetive set
284        geom->addPrimitiveSet(_triangles.get());
285
286        // if color info is given set the color array
287        if(_colors.valid())
288        {
289            geom->setColorArray(_colors.get());
290            geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
291           
292        }
293
294       
295        // set flage true to activate the vertex buffer object of drawable
296        geom->setUseVertexBufferObjects(true);
297       
298
299        osg::Geode* geode = new osg::Geode;
300        geode->addDrawable(geom);
301        return geode;
302   }
303   
304    return NULL;
305}
306
307
308/*  Calculate the face or vertex normals of the current vertex data.  */
309void VertexData::_calculateNormals( const bool vertexNormals )
310{
311
312    if(_normals.valid())
313        return;
314
315    #ifndef NDEBUG
316    int wrongNormals = 0;
317    #endif
318
319    if(!_normals.valid())
320    {
321        _normals = new osg::Vec3Array;
322    }
323   
324    //normals.clear();
325    if( vertexNormals )
326    {
327        // initialize all normals to zero
328        for( size_t i = 0; i < _vertices->size(); ++i )
329        {
330            _normals->push_back( osg::Vec3( 0, 0, 0 ) );
331        }
332    }
333
334   
335    for( size_t i = 0; i < ((_triangles->size()));  i += 3 )
336    {
337        // iterate over all triangles and add their normals to adjacent vertices
338        Normal  triangleNormal;
339        unsigned int i0, i1, i2;
340        i0 = (*_triangles)[i+0];
341        i1 = (*_triangles)[i+1];
342        i2 = (*_triangles)[i+2];
343        triangleNormal.normal((*_vertices)[i0],
344                               (*_vertices)[i1],
345                               (*_vertices)[i2] );
346       
347        // count emtpy normals in debug mode
348        #ifndef NDEBUG
349        if( triangleNormal.triNormal.length() == 0.0f )
350            ++wrongNormals;
351        #endif
352         
353        if( vertexNormals )
354        {
355            (*_normals)[i0] += triangleNormal.triNormal;
356            (*_normals)[i1] += triangleNormal.triNormal;
357            (*_normals)[i2] += triangleNormal.triNormal;
358        }
359        else
360            _normals->push_back( triangleNormal.triNormal );
361    }
362   
363    // normalize all the normals
364    if( vertexNormals )
365        for( size_t i = 0; i < _normals->size(); ++i )
366            (*_normals)[i].normalize();
367   
368    #ifndef NDEBUG
369    if( wrongNormals > 0 )
370        MESHINFO << wrongNormals << " faces had no valid normal." << endl;
371    #endif
372}
Note: See TracBrowser for help on using the browser.