diff --git a/src/osgPlugins/ply/plyfile.cpp b/src/osgPlugins/ply/plyfile.cpp index 5754464c3..86934a3d6 100644 --- a/src/osgPlugins/ply/plyfile.cpp +++ b/src/osgPlugins/ply/plyfile.cpp @@ -45,6 +45,8 @@ WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. #include #include #include +#include +#include #include #include @@ -1052,6 +1054,35 @@ void ply_get_element_setup( PlyFile *plyfile, char *elem_name, int nprops, } } +void ply_set_property( + PlyProperty *prop, + PlyProperty *prop_ptr, + PlyElement *elem, + const int &index +) +{ + prop_ptr->internal_type = prop->internal_type; + prop_ptr->offset = prop->offset; + prop_ptr->count_internal = prop->count_internal; + prop_ptr->count_offset = prop->count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; +} + +// Tokenize a property using the given delimiter +void tokenizeProperties(const char* pnames, std::vector &tokens, const std::string &delimiter) +{ + std::string propNames(pnames); + std::string::size_type lastPos = propNames.find_first_not_of(delimiter, 0); + std::string::size_type pos = propNames.find_first_of(delimiter, lastPos); + + while (std::string::npos != pos || std::string::npos != lastPos) { + tokens.push_back(propNames.substr(lastPos, pos - lastPos)); + lastPos = propNames.find_first_not_of(delimiter, pos); + pos = propNames.find_first_of(delimiter, lastPos); + } +} /****************************************************************************** Specify a property of an element that is to be returned. This should be @@ -1072,7 +1103,7 @@ void ply_get_property( ) { PlyElement *elem; - PlyProperty *prop_ptr; + PlyProperty *prop_ptr = 0; int index; /* find information about the element */ @@ -1080,20 +1111,27 @@ void ply_get_property( plyfile->which_elem = elem; /* deposit the property information into the element's description */ + /* Properties may have several names, separated by | with no spaces */ + std::vector tokens; + tokenizeProperties(prop->name, tokens, "|"); - prop_ptr = find_property (elem, prop->name, &index); - if (prop_ptr == NULL) { + for(std::vector::iterator it_property = tokens.begin(); + !prop_ptr && it_property != tokens.end(); + ++it_property) + { + prop_ptr = find_property(elem, it_property->c_str(), &index); + } + + if(prop_ptr) + { + ply_set_property(prop, prop_ptr, elem, index); + } + else + { fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", prop->name, elem_name); return; } - prop_ptr->internal_type = prop->internal_type; - prop_ptr->offset = prop->offset; - prop_ptr->count_internal = prop->count_internal; - prop_ptr->count_offset = prop->count_offset; - - /* specify that the user wants this property */ - elem->store_prop[index] = STORE_PROP; } diff --git a/src/osgPlugins/ply/vertexData.cpp b/src/osgPlugins/ply/vertexData.cpp index 209c5295d..c8718b1a8 100644 --- a/src/osgPlugins/ply/vertexData.cpp +++ b/src/osgPlugins/ply/vertexData.cpp @@ -17,25 +17,12 @@ #include #include #include +#include using namespace std; using namespace ply; -struct Normal{ - osg::Vec3 triNormal; - void normal(osg::Vec3 v1, osg::Vec3 v2, osg::Vec3 v3) - { - osg::Vec3 u,v; - - // right hand system, CCW triangle - u = v2 - v1; - v = v3 - v1; - triNormal = u^v; - triNormal.normalize(); - } -}; - /* Contructor. */ VertexData::VertexData() : _invertFaces( false ) @@ -215,7 +202,7 @@ void VertexData::readTriangles( PlyFile* file, const int nFaces ) PlyProperty faceProps[] = { - { "vertex_indices", PLY_INT, PLY_INT, offsetof( _Face, vertices ), + { "vertex_indices|vertex_index", PLY_INT, PLY_INT, offsetof( _Face, vertices ), 1, PLY_UCHAR, PLY_UCHAR, offsetof( _Face, nVertices ) } }; @@ -225,25 +212,31 @@ void VertexData::readTriangles( PlyFile* file, const int nFaces ) //triangles.reserve( nFaces ); if(!_triangles.valid()) _triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0); + if(!_quads.valid()) + _quads = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); - // read in the faces, asserting that they are only triangles - int ind1 = _invertFaces ? 2 : 0; - int ind3 = _invertFaces ? 0 : 2; - for( int i = 0; i < nFaces; ++i ) + // read the faces, reversing the reading direction if _invertFaces is true + for( int i = 0 ; i < nFaces; i++ ) { ply_get_element( file, static_cast< void* >( &face ) ); MESHASSERT( face.vertices != 0 ); - if( (unsigned int)(face.nVertices) != 3 ) + if( (unsigned int)(face.nVertices) > 4 ) { free( face.vertices ); throw MeshException( "Error reading PLY file. Encountered a " - "face which does not have three vertices." ); + "face which does not have three or four vertices." ); + } + + unsigned short index; + for(int j = 0 ; j < face.nVertices ; j++) + { + index = ( _invertFaces ? face.nVertices - 1 - j : j ); + if(face.nVertices == 4) + _quads->push_back(face.vertices[index]); + else + _triangles->push_back(face.vertices[index]); } - // Add the face indices in the premitive set - _triangles->push_back( face.vertices[ind1]); - _triangles->push_back( face.vertices[1]); - _triangles->push_back( face.vertices[ind3] ); // free the memory that was allocated by ply_get_element free( face.vertices ); @@ -353,7 +346,7 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor fields |= DIFFUSE; if( equal_strings( props[j]->name, "specular_red" ) ) fields |= SPECULAR; - } + } if( ignoreColors ) { @@ -408,7 +401,10 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor // Read Triangles readTriangles( file, nElems ); // Check whether all face elements read or not - MESHASSERT( _triangles->size()/3 == static_cast< size_t >( nElems ) ); + unsigned int nbTriangles = (_triangles.valid() ? _triangles->size() / 3 : 0) ; + unsigned int nbQuads = (_quads.valid() ? _quads->size() / 4 : 0 ); + + MESHASSERT( (nbTriangles + nbQuads) == static_cast< size_t >( nElems ) ); result = true; } catch( exception& e ) @@ -442,23 +438,22 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor // set the vertex array geom->setVertexArray(_vertices.get()); - // If the normals are not calculated calculate the normals for faces - if(_triangles.valid()) + // Add the primitive set + bool hasTriOrQuads = false; + if (_triangles.valid() && _triangles->size() > 0 ) { - if(!_normals.valid()) - _calculateNormals(); - } - - // Set the normals - if (_normals.valid()) - { - geom->setNormalArray(_normals.get(), osg::Array::BIND_PER_VERTEX); + geom->addPrimitiveSet(_triangles.get()); + hasTriOrQuads = true; } - // Add the primitive set - if (_triangles.valid() && _triangles->size() > 0 ) - geom->addPrimitiveSet(_triangles.get()); - else + if (_quads.valid() && _quads->size() > 0 ) + { + geom->addPrimitiveSet(_quads.get()); + hasTriOrQuads = true; + } + + // Print points if the file contains unsupported primitives + if(!hasTriOrQuads) geom->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, _vertices->size())); @@ -483,6 +478,17 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor geom->setColorArray(_specular.get(), osg::Array::BIND_PER_VERTEX ); } + // If the model has normals, add them to the geometry + if(_normals.valid()) + { + geom->setNormalArray(_normals.get(), osg::Array::BIND_PER_VERTEX); + } + else + { // If not, use the smoothing visitor to generate them + // (quads will be triangulated by the smoothing visitor) + osgUtil::SmoothingVisitor::smooth((*geom), osg::PI/2); + } + // set flage true to activate the vertex buffer object of drawable geom->setUseVertexBufferObjects(true); @@ -496,69 +502,3 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor } -/* Calculate the face or vertex normals of the current vertex data. */ -void VertexData::_calculateNormals( const bool vertexNormals ) -{ - - if(_normals.valid()) - return; - - #ifndef NDEBUG - int wrongNormals = 0; - #endif - - if(!_normals.valid()) - { - _normals = new osg::Vec3Array; - } - - //normals.clear(); - if( vertexNormals ) - { - // initialize all normals to zero - for( size_t i = 0; i < _vertices->size(); ++i ) - { - _normals->push_back( osg::Vec3( 0, 0, 0 ) ); - } - } - - - for( size_t i = 0; i < ((_triangles->size())); i += 3 ) - { - // iterate over all triangles and add their normals to adjacent vertices - Normal triangleNormal; - unsigned int i0, i1, i2; - i0 = (*_triangles)[i+0]; - i1 = (*_triangles)[i+1]; - i2 = (*_triangles)[i+2]; - triangleNormal.normal((*_vertices)[i0], - (*_vertices)[i1], - (*_vertices)[i2] ); - - // count emtpy normals in debug mode - #ifndef NDEBUG - if( triangleNormal.triNormal.length() == 0.0f ) - ++wrongNormals; - #endif - - if( vertexNormals ) - { - (*_normals)[i0] += triangleNormal.triNormal; - (*_normals)[i1] += triangleNormal.triNormal; - (*_normals)[i2] += triangleNormal.triNormal; - } - else - _normals->push_back( triangleNormal.triNormal ); - } - - // normalize all the normals - if( vertexNormals ) - for( size_t i = 0; i < _normals->size(); ++i ) - (*_normals)[i].normalize(); - - #ifndef NDEBUG - if( wrongNormals > 0 ) - MESHINFO << wrongNormals << " faces had no valid normal." << endl; - #endif -} - diff --git a/src/osgPlugins/ply/vertexData.h b/src/osgPlugins/ply/vertexData.h index 89e9b1fda..dec0a663a 100644 --- a/src/osgPlugins/ply/vertexData.h +++ b/src/osgPlugins/ply/vertexData.h @@ -66,11 +66,6 @@ namespace ply // Reads the triangle indices from the ply file void readTriangles( PlyFile* file, const int nFaces ); - // Calculates the normals according to passed flag - // if vertexNormals is true then computes normal per vertices - // otherwise per triangle means per face - void _calculateNormals( const bool vertexNormals = true ); - bool _invertFaces; // Vertex array in osg format @@ -85,6 +80,7 @@ namespace ply osg::ref_ptr _normals; // The indices of the faces in premitive set osg::ref_ptr _triangles; + osg::ref_ptr _quads; }; }