Hello Robert,

attached is an extension to the PLY plugin to read files with textures.

Regards,
 Uwe


--

           \\\|/// *HLRS, High Performance Computing Center Stuttgart*
 _I_       ( o o )                *Visualization/VR*             _I_
(_@_)--oo0O--(_)--O0oo------------------------------------------(_@_)
 | | Dr.-Ing. Uwe Woessner  http://www.hlrs.de/people/woessner/  | |
 | |       .ooo0                 mobile: +49-173-7028729         | |
 |_|       (   )  Oooo.         office: +49-711-6856-5790        |_|
(_@_)-------\ (---(   )-----------------------------------------(_@_)
  I          \_)   ) /                                            I
                  (_/

/*
    vertexData.cpp
    Copyright (c) 2007, Tobias Wolf <tw...@access.unizh.ch>
    All rights reserved.

    Implementation of the VertexData class.
*/

/** note, derived from Equalizer LGPL source.*/

#include "typedefs.h"
#include "vertexData.h"
#include "ply.h"

#include <cstdlib>
#include <algorithm>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/io_utils>
#include <osgUtil/SmoothingVisitor>
#include <osg/TexEnv>
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
#include <osg/Texture2D>

using namespace std;
using namespace ply;


/*  Contructor.  */
VertexData::VertexData()
    : _invertFaces( false )
{
    // Initialize the members
    _vertices = NULL;
    _colors = NULL;
    _normals = NULL;
    _triangles = NULL;
    _diffuse = NULL;
    _ambient = NULL;
        _specular = NULL;
        _texcoord = NULL;
}


/*  Read the vertex and (if available/wanted) color data from the open file.  */
void VertexData::readVertices( PlyFile* file, const int nVertices,
                               const int fields )
{
    // temporary vertex structure for ply loading
    struct _Vertex
    {
        float           x;
        float           y;
        float           z;
        float           nx;
        float           ny;
        float           nz;
        unsigned char   red;
        unsigned char   green;
        unsigned char   blue;
        unsigned char   alpha;
        unsigned char   ambient_red;
        unsigned char   ambient_green;
        unsigned char   ambient_blue;
        unsigned char   diffuse_red;
        unsigned char   diffuse_green;
        unsigned char   diffuse_blue;
        unsigned char   specular_red;
        unsigned char   specular_green;
        unsigned char   specular_blue;
        float           specular_coeff;
        float           specular_power;
                float texture_u;
                float texture_v;
    } vertex;

    PlyProperty vertexProps[] =
    {
        { "x", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, x ), 0, 0, 0, 0 },
        { "y", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, y ), 0, 0, 0, 0 },
        { "z", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, z ), 0, 0, 0, 0 },
        { "nx", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, nx ), 0, 0, 0, 0 },
                { "ny", PLY_FLOAT, PLY_FLOAT, offsetof(_Vertex, ny), 0, 0, 0, 0 
},
                { "nz", PLY_FLOAT, PLY_FLOAT, offsetof(_Vertex, nz), 0, 0, 0, 0 
},
        { "red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, red ), 0, 0, 0, 0 },
        { "green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, green ), 0, 0, 0, 0 
},
        { "blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, blue ), 0, 0, 0, 0 },
        { "alpha", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, alpha ), 0, 0, 0, 0 
},
        { "ambient_red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, ambient_red 
), 0, 0, 0, 0 },
        { "ambient_green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, 
ambient_green ), 0, 0, 0, 0 },
        { "ambient_blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, ambient_blue 
), 0, 0, 0, 0 },
        { "diffuse_red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, diffuse_red 
), 0, 0, 0, 0 },
        { "diffuse_green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, 
diffuse_green ), 0, 0, 0, 0 },
        { "diffuse_blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, diffuse_blue 
), 0, 0, 0, 0 },
        { "specular_red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, specular_red 
), 0, 0, 0, 0 },
        { "specular_green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, 
specular_green ), 0, 0, 0, 0 },
        { "specular_blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, 
specular_blue ), 0, 0, 0, 0 },
        { "specular_coeff", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, 
specular_coeff ), 0, 0, 0, 0 },
        { "specular_power", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, 
specular_power ), 0, 0, 0, 0 },
                { "texture_u", PLY_FLOAT, PLY_FLOAT, offsetof(_Vertex, 
texture_u), 0, 0, 0, 0 },
                { "texture_v", PLY_FLOAT, PLY_FLOAT, offsetof(_Vertex, 
texture_v), 0, 0, 0, 0 },
    };

    // use all 6 properties when reading colors, only the first 3 otherwise
    for( int i = 0; i < 3; ++i )
        ply_get_property( file, "vertex", &vertexProps[i] );

    if (fields & NORMALS)
      for( int i = 3; i < 6; ++i )
        ply_get_property( file, "vertex", &vertexProps[i] );

    if (fields & RGB)
      for( int i = 6; i < 9; ++i )
        ply_get_property( file, "vertex", &vertexProps[i] );

    if (fields & RGBA)
        ply_get_property( file, "vertex", &vertexProps[9] );

    if (fields & AMBIENT)
      for( int i = 10; i < 13; ++i )
        ply_get_property( file, "vertex", &vertexProps[i] );

    if (fields & DIFFUSE)
      for( int i = 13; i < 16; ++i )
        ply_get_property( file, "vertex", &vertexProps[i] );

    if (fields & SPECULAR)
      for( int i = 16; i < 21; ++i )
        ply_get_property( file, "vertex", &vertexProps[i] );

        if (fields & TEXCOORD)
                for (int i = 21; i < 23; ++i)
                        ply_get_property(file, "vertex", &vertexProps[i]);

    // check whether array is valid otherwise allocate the space
    if(!_vertices.valid())
        _vertices = new osg::Vec3Array;

    if( fields & NORMALS )
    {
        if(!_normals.valid())
            _normals = new osg::Vec3Array;
    }

    // If read colors allocate space for color array
    if( fields & RGB || fields & RGBA)
    {
        if(!_colors.valid())
            _colors = new osg::Vec4Array;
    }

    if( fields & AMBIENT )
    {
        if(!_ambient.valid())
            _ambient = new osg::Vec4Array;
    }

    if( fields & DIFFUSE )
    {
        if(!_diffuse.valid())
            _diffuse = new osg::Vec4Array;
    }

    if( fields & SPECULAR )
    {
        if(!_specular.valid())
            _specular = new osg::Vec4Array;
    }
        if (fields & TEXCOORD)
        {
                if (!_texcoord.valid())
                        _texcoord = new osg::Vec2Array;
        }

    // read in the vertices
    for( int i = 0; i < nVertices; ++i )
    {
        ply_get_element( file, static_cast< void* >( &vertex ) );
        _vertices->push_back( osg::Vec3( vertex.x, vertex.y, vertex.z ) );
        if (fields & NORMALS)
            _normals->push_back( osg::Vec3( vertex.nx, vertex.ny, vertex.nz ) );

        if( fields & RGBA )
            _colors->push_back( osg::Vec4( (unsigned int) vertex.red / 255.0,
                                           (unsigned int) vertex.green / 255.0 ,
                                           (unsigned int) vertex.blue / 255.0,
                                           (unsigned int) vertex.alpha / 255.0) 
);
        else if( fields & RGB )
            _colors->push_back( osg::Vec4( (unsigned int) vertex.red / 255.0,
                                           (unsigned int) vertex.green / 255.0 ,
                                           (unsigned int) vertex.blue / 255.0, 
1.0 ) );
        if( fields & AMBIENT )
            _ambient->push_back( osg::Vec4( (unsigned int) vertex.ambient_red / 
255.0,
                                            (unsigned int) vertex.ambient_green 
/ 255.0 ,
                                            (unsigned int) vertex.ambient_blue 
/ 255.0, 1.0 ) );

        if( fields & DIFFUSE )
            _diffuse->push_back( osg::Vec4( (unsigned int) vertex.diffuse_red / 
255.0,
                                            (unsigned int) vertex.diffuse_green 
/ 255.0 ,
                                            (unsigned int) vertex.diffuse_blue 
/ 255.0, 1.0 ) );

        if( fields & SPECULAR )
            _specular->push_back( osg::Vec4( (unsigned int) vertex.specular_red 
/ 255.0,
                                             (unsigned int) 
vertex.specular_green / 255.0 ,
                                             (unsigned int) 
vertex.specular_blue / 255.0, 1.0 ) );
                if (fields & TEXCOORD)
                        
_texcoord->push_back(osg::Vec2(vertex.texture_u,vertex.texture_v));
    }
}


/*  Read the index data from the open file.  */
void VertexData::readTriangles( PlyFile* file, const int nFaces )
{
    // temporary face structure for ply loading
    struct _Face
    {
        unsigned char   nVertices;
        int*            vertices;
    } face;

    PlyProperty faceProps[] =
    {
        { "vertex_indices|vertex_index", PLY_INT, PLY_INT, offsetof( _Face, 
vertices ),
          1, PLY_UCHAR, PLY_UCHAR, offsetof( _Face, nVertices ) }
    };

    ply_get_property( file, "face", &faceProps[0] );

    if(!_triangles.valid())
        _triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);

    if(!_quads.valid())
        _quads = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS);


    const char NUM_VERTICES_TRIANGLE(3);
    const char NUM_VERTICES_QUAD(4);

    // read the faces, reversing the reading direction if _invertFaces is true
    for( int i = 0 ; i < nFaces; i++ )
    {
        // initialize face values
        face.nVertices = 0;
        face.vertices = 0;

        ply_get_element( file, static_cast< void* >( &face ) );
        if (face.vertices)
        {
            if (face.nVertices == NUM_VERTICES_TRIANGLE ||  face.nVertices == 
NUM_VERTICES_QUAD)
            {
                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]);
                }
            }
            // free the memory that was allocated by ply_get_element
            free( face.vertices );
        }
    }
}


/*  Open a PLY file and read vertex, color and index data. and returns the node 
 */
osg::Node* VertexData::readPlyFile( const char* filename, const bool 
ignoreColors )
{
    int     nPlyElems;
    char**  elemNames;
    int     fileType;
    float   version;
    bool    result = false;
    int     nComments;
    char**  comments;

    PlyFile* file = NULL;

    // Try to open ply file as for reading
    try{
            file  = ply_open_for_reading( const_cast< char* >( filename ),
                                          &nPlyElems, &elemNames,
                                          &fileType, &version );
    }
    // Catch the if any exception thrown
    catch( exception& e )
    {
        MESHERROR << "Unable to read PLY file, an exception occurred:  "
                    << e.what() << endl;
    }

    if( !file )
    {
        MESHERROR << "Unable to open PLY file " << filename
                  << " for reading." << endl;
        return NULL;
    }

    MESHASSERT( elemNames != 0 );


    nComments = file->num_comments;
    comments = file->comments;


    #ifndef NDEBUG
    MESHINFO << filename << ": " << nPlyElems << " elements, file type = "
             << fileType << ", version = " << version << endl;
    #endif
        char *textureFile = NULL;
    for( int i = 0; i < nComments; i++ )
    {
        if( equal_strings( comments[i], "modified by flipply" ) )
        {
            _invertFaces = true;
        }
                if (strncmp(comments[i], "TextureFile",11)==0)
                {
                        textureFile = comments[i]+12;
                        char * path = new 
char[strlen(const_cast<char*>(filename)) + 1 + strlen(comments[i])];
                        if (textureFile[0] == '\\' || textureFile[0] == '/' || 
textureFile[1] == ':')
                        {
                                // texture filename is absolute
                                strcpy(path, textureFile);
                        }
                        else
                        {
                                // texture filename is relative
                                // add directory of ply file
                                strcpy(path, const_cast<char*>(filename));
                                char *pp = path + strlen(path);
                                while (pp >= path)
                                {
                                        if (*pp == '\\' || *pp == '/')
                                        {
                                                pp++;
                                                *pp = '\0';
                                                break;
                                        }
                                        pp--;
                                }
                                if (pp == path - 1)
                                {
                                        pp++;
                                        *pp = '\0';
                                }
                                strcat(path, textureFile);
                        }
                        textureFile = path;
                }

    }
    for( int i = 0; i < nPlyElems; ++i )
    {
        int nElems;
        int nProps;

        PlyProperty** props = NULL;
        try{
                props = ply_get_element_description( file, elemNames[i],
                                                     &nElems, &nProps );
        }
        catch( exception& e )
        {
            MESHERROR << "Unable to get PLY file description, an exception 
occurred:  "
                        << e.what() << endl;
        }
        MESHASSERT( props != 0 );

        #ifndef NDEBUG
        MESHINFO << "element " << i << ": name = " << elemNames[i] << ", "
                 << nProps << " properties, " << nElems << " elements" << endl;
        for( int j = 0; j < nProps; ++j )
        {
            MESHINFO << "element " << i << ", property " << j << ": "
                     << "name = " << props[j]->name << endl;
        }
        #endif

        // if the string is vertex means vertex data is started
        if( equal_strings( elemNames[i], "vertex" ) )
        {
            int fields = NONE;
            // determine if the file stores vertex colors
            for( int j = 0; j < nProps; ++j )
              {
                // if the string have the red means color info is there
                if( equal_strings( props[j]->name, "x" ) )
                    fields |= XYZ;
                if( equal_strings( props[j]->name, "nx" ) )
                    fields |= NORMALS;
                if( equal_strings( props[j]->name, "alpha" ) )
                    fields |= RGBA;
                if ( equal_strings( props[j]->name, "red" ) )
                    fields |= RGB;
                if( equal_strings( props[j]->name, "ambient" ) )
                    fields |= AMBIENT;
                if( equal_strings( props[j]->name, "diffuse_red" ) )
                    fields |= DIFFUSE;
                                if (equal_strings(props[j]->name, 
"specular_red"))
                                        fields |= SPECULAR;
                                if (equal_strings(props[j]->name, "texture_u"))
                                        fields |= TEXCOORD;
                                if (equal_strings(props[j]->name, "texture_v"))
                                        fields |= TEXCOORD;
          }

            if( ignoreColors )
              {
                fields &= ~(XYZ | NORMALS);
                MESHINFO << "Colors in PLY file ignored per request." << endl;
              }

            try {
                // Read vertices and store in a std::vector array
                readVertices( file, nElems, fields );
                // Check whether all vertices are loaded or not
                MESHASSERT( _vertices->size() == static_cast< size_t >( nElems 
) );

                // Check if all the optional elements were read or not
                if( fields & NORMALS )
                {
                    MESHASSERT( _normals->size() == static_cast< size_t >( 
nElems ) );
                }
                if( fields & RGB || fields & RGBA)
                {
                    MESHASSERT( _colors->size() == static_cast< size_t >( 
nElems ) );
                }
                if( fields & AMBIENT )
                {
                    MESHASSERT( _ambient->size() == static_cast< size_t >( 
nElems ) );
                }
                if( fields & DIFFUSE )
                {
                    MESHASSERT( _diffuse->size() == static_cast< size_t >( 
nElems ) );
                }
                                if (fields & SPECULAR)
                                {
                                        MESHASSERT(_specular->size() == 
static_cast< size_t >(nElems));
                                }
                                if (fields & TEXCOORD)
                                {
                                        MESHASSERT(_texcoord->size() == 
static_cast< size_t >(nElems));
                                }

                result = true;
            }
            catch( exception& e )
            {
                MESHERROR << "Unable to read vertex in PLY file, an exception 
occurred:  "
                            << e.what() << endl;
                // stop for loop by setting the loop variable to break condition
                // this way resources still get released even on error cases
                i = nPlyElems;

            }
        }
        // If the string is face means triangle info started
        else if( equal_strings( elemNames[i], "face" ) )
        try
        {
            // Read Triangles
            readTriangles( file, nElems );
            // Check whether all face elements read or not
#if DEBUG
            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 ) );
#endif
            result = true;
        }
        catch( exception& e )
        {
            MESHERROR << "Unable to read PLY file, an exception occurred:  "
                      << e.what() << endl;
            // stop for loop by setting the loop variable to break condition
            // this way resources still get released even on error cases
            i = nPlyElems;
        }

        // free the memory that was allocated by ply_get_element_description
        for( int j = 0; j < nProps; ++j )
            free( props[j] );
        free( props );
    }

    ply_close( file );

    // free the memory that was allocated by ply_open_for_reading
    for( int i = 0; i < nPlyElems; ++i )
        free( elemNames[i] );
    free( elemNames );

   // If the result is true means the ply file is successfully read
   if(result)
   {
        // Create geometry node
        osg::Geometry* geom  =  new osg::Geometry;

        // set the vertex array
        geom->setVertexArray(_vertices.get());

        // Add the primitive set
        bool hasTriOrQuads = false;
        if (_triangles.valid() && _triangles->size() > 0 )
        {
            geom->addPrimitiveSet(_triangles.get());
            hasTriOrQuads = true;
        }

        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()));


        // Apply the colours to the model; at the moment this is a
        // kludge because we only use one kind and apply them all the
        // same way. Also, the priority order is completely arbitrary

        if(_colors.valid())
        {
            geom->setColorArray(_colors.get(), osg::Array::BIND_PER_VERTEX );
        }
        else if(_ambient.valid())
        {
            geom->setColorArray(_ambient.get(), osg::Array::BIND_PER_VERTEX );
        }
        else if(_diffuse.valid())
        {
            geom->setColorArray(_diffuse.get(), osg::Array::BIND_PER_VERTEX );
        }
        else if(_specular.valid())
        {
            geom->setColorArray(_specular.get(), osg::Array::BIND_PER_VERTEX );
        }
        else if (_texcoord.valid())
        {
                geom->setTexCoordArray(0, _texcoord);
        }

        // 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);

                osg::Image *image = NULL;
                if (textureFile && (image = osgDB::readImageFile(textureFile)) 
!= NULL)
                {
                        osg::Texture2D *texture = new osg::Texture2D;
                        texture->setImage(image);
                        texture->setResizeNonPowerOfTwoHint(false);

                        osg::TexEnv *texenv = new osg::TexEnv;
                        texenv->setMode(osg::TexEnv::REPLACE);

                        osg::StateSet *stateset = geom->getOrCreateStateSet();
                        stateset->setTextureAttributeAndModes(0, texture, 
osg::StateAttribute::ON);
                        stateset->setTextureAttribute(0, texenv);
                        delete[] textureFile;
                }

        osg::Geode* geode = new osg::Geode;
        geode->addDrawable(geom);
        return geode;
   }

    return NULL;
}


/*
    vertexData.h
    Copyright (c) 2007, Tobias Wolf <tw...@access.unizh.ch>
    All rights reserved.

    Header file of the VertexData class.
*/

/** note, derived from Equalizer LGPL source.*/


#ifndef MESH_VERTEXDATA_H
#define MESH_VERTEXDATA_H


#include <osg/Node>
#include <osg/PrimitiveSet>

#include <vector>

///////////////////////////////////////////////////////////////////////////////
//!
//! \class VertexData
//! \brief helps to read ply file and converts in to osg::Node format
//!
///////////////////////////////////////////////////////////////////////////////

// defined elsewhere
struct PlyFile;

namespace ply
{
    /*  Holds the flat data and offers routines to read, scale and sort it.  */
    class VertexData
    {
    public:
        // Default constructor
        VertexData();


        // Reads ply file and convert in to osg::Node and returns the same
        osg::Node* readPlyFile( const char* file, const bool ignoreColors = 
false );

        // to set the flag for using inverted face
        void useInvertedFaces() { _invertFaces = true; }

    private:

        enum VertexFields
        {
          NONE = 0,
          XYZ = 1,
          NORMALS = 2,
          RGB = 4,
          AMBIENT = 8,
          DIFFUSE = 16,
          SPECULAR = 32,
                  RGBA = 64,
                  TEXCOORD = 128
        };

        // Function which reads all the vertices and colors if color info is
        // given and also if the user wants that information
        void readVertices( PlyFile* file, const int nVertices,
                           const int vertexFields );

        // Reads the triangle indices from the ply file
        void readTriangles( PlyFile* file, const int nFaces );

        bool        _invertFaces;

        // Vertex array in osg format
        osg::ref_ptr<osg::Vec3Array>   _vertices;
        // Color array in osg format
        osg::ref_ptr<osg::Vec4Array>   _colors;
        osg::ref_ptr<osg::Vec4Array>   _ambient;
        osg::ref_ptr<osg::Vec4Array>   _diffuse;
                osg::ref_ptr<osg::Vec4Array>   _specular;
                osg::ref_ptr<osg::Vec2Array>   _texcoord;

        // Normals in osg format
        osg::ref_ptr<osg::Vec3Array> _normals;
        // The indices of the faces in premitive set
        osg::ref_ptr<osg::DrawElementsUInt> _triangles;
        osg::ref_ptr<osg::DrawElementsUInt> _quads;
    };
}


#endif // MESH_VERTEXDATA_H
_______________________________________________
osg-submissions mailing list
osg-submissions@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to