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."
This commit is contained in:
Robert Osfield
2009-04-09 18:26:04 +00:00
parent 102330f42b
commit 9a42888bdc
7 changed files with 3513 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
#this file is automatically generated
SET(TARGET_SRC ReaderWriterPLY.cpp
vertexData.cpp
plyfile.cpp
)
SET(TARGET_H
typedefs.h
ply.h
vertexData.h
)
#### end var setup ###
SETUP_PLUGIN(ply)

View File

@@ -0,0 +1,81 @@
/*
* PLY ( Stanford Triangle Format ) File Loader for OSG
* Copyright (C) 2009 by VizExperts Limited
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include "vertexData.h"
using namespace osg;
using namespace osgDB;
using namespace std;
///////////////////////////////////////////////////////////////////////////////
//!
//! \class ReaderWriterPLY
//! \brief This is the Reader for the ply file format
//!
//////////////////////////////////////////////////////////////////////////////
class ReaderWriterPLY : public osgDB::ReaderWriter
{
public:
ReaderWriterPLY()
{
supportsExtension("ply","Stanford Triangle Format");
}
virtual const char* className() { return "ReaderWriterPLY"; }
virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options*) const;
protected:
};
// register with Registry to instantiate the above reader/writer.
REGISTER_OSGPLUGIN(ply, ReaderWriterPLY)
///////////////////////////////////////////////////////////////////////////////
//!
//! \brief Function which is called when any ply file is requested to load in
//! \osgDB. Load read ply file and if it successes return the osg::Node
//!
///////////////////////////////////////////////////////////////////////////////
osgDB::ReaderWriter::ReadResult ReaderWriterPLY::readNode(const std::string& filename, const osgDB::ReaderWriter::Options* options) const
{
// Get the file extension
std::string ext = osgDB::getFileExtension(filename);
// If the file extension does not support then return that file is not handled
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
// Check whether or not file exist or not
std::string fileName = osgDB::findDataFile(filename, options);
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
//Instance of vertex data which will read the ply file and convert in to osg::Node
ply::VertexData vertexData;
osg::Node* node = vertexData.readPlyFile(filename.c_str());
if (node)
return node;
return ReadResult::FILE_NOT_HANDLED;
}

172
src/osgPlugins/ply/ply.h Normal file
View File

@@ -0,0 +1,172 @@
/*
Header for PLY polygon files.
- Greg Turk, March 1994
A PLY file contains a single polygonal _object_.
An object is composed of lists of _elements_. Typical elements are
vertices, faces, edges and materials.
Each type of element for a given object has one or more _properties_
associated with the element type. For instance, a vertex element may
have as properties three floating-point values x,y,z and three unsigned
chars for red, green and blue.
---------------------------------------------------------------
Copyright (c) 1994 The Board of Trustees of The Leland Stanford
Junior University. All rights reserved.
Permission to use, copy, modify and distribute this software and its
documentation for any purpose is hereby granted without fee, provided
that the above copyright notice and this permission notice appear in
all copies of this software and that you do not sell the software.
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef __PLY_H__
#define __PLY_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stddef.h>
#define PLY_ASCII 1 /* ascii PLY file */
#define PLY_BINARY_BE 2 /* binary PLY file, big endian */
#define PLY_BINARY_LE 3 /* binary PLY file, little endian */
#define PLY_OKAY 0 /* ply routine worked okay */
#define PLY_ERROR -1 /* error in ply routine */
/* scalar data types supported by PLY format */
#define PLY_START_TYPE 0
#define PLY_CHAR 1
#define PLY_SHORT 2
#define PLY_INT 3
#define PLY_UCHAR 4
#define PLY_USHORT 5
#define PLY_UINT 6
#define PLY_FLOAT 7
#define PLY_DOUBLE 8
#define PLY_FLOAT32 9
#define PLY_UINT8 10
#define PLY_INT32 11
#define PLY_END_TYPE 12
#define PLY_SCALAR 0
#define PLY_LIST 1
typedef struct PlyProperty { /* description of a property */
char *name; /* property name */
int external_type; /* file's data type */
int internal_type; /* program's data type */
int offset; /* offset bytes of prop in a struct */
int is_list; /* 1 = list, 0 = scalar */
int count_external; /* file's count type */
int count_internal; /* program's count type */
int count_offset; /* offset byte for list count */
} PlyProperty;
typedef struct PlyElement { /* description of an element */
char *name; /* element name */
int num; /* number of elements in this object */
int size; /* size of element (bytes) or -1 if variable */
int nprops; /* number of properties for this element */
PlyProperty **props; /* list of properties in the file */
char *store_prop; /* flags: property wanted by user? */
int other_offset; /* offset to un-asked-for props, or -1 if none*/
int other_size; /* size of other_props structure */
} PlyElement;
typedef struct PlyOtherProp { /* describes other properties in an element */
char *name; /* element name */
int size; /* size of other_props */
int nprops; /* number of properties in other_props */
PlyProperty **props; /* list of properties in other_props */
} PlyOtherProp;
typedef struct OtherData { /* for storing other_props for an other element */
void *other_props;
} OtherData;
typedef struct OtherElem { /* data for one "other" element */
char *elem_name; /* names of other elements */
int elem_count; /* count of instances of each element */
OtherData **other_data; /* actual property data for the elements */
PlyOtherProp *other_props; /* description of the property data */
} OtherElem;
typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */
int num_elems; /* number of other elements */
OtherElem *other_list; /* list of data for other elements */
} PlyOtherElems;
typedef struct PlyFile { /* description of PLY file */
FILE *fp; /* file pointer */
int file_type; /* ascii or binary */
float version; /* version number of file */
int nelems; /* number of elements of object */
PlyElement **elems; /* list of elements */
int num_comments; /* number of comments */
char **comments; /* list of comments */
int num_obj_info; /* number of items of object information */
char **obj_info; /* list of object info items */
PlyElement *which_elem; /* which element we're currently writing */
PlyOtherElems *other_elems; /* "other" elements from a PLY file */
} PlyFile;
/* memory allocation */
extern char *my_alloc();
#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__)
/*** delcaration of routines ***/
extern PlyFile *ply_write(FILE *, int, char **, int);
extern PlyFile *ply_open_for_writing(char *, int, char **, int, float *);
extern void ply_describe_element(PlyFile *, char *, int, int, PlyProperty *);
extern void ply_describe_property(PlyFile *, char *, PlyProperty *);
extern void ply_element_count(PlyFile *, const char *, int);
extern void ply_header_complete(PlyFile *);
extern void ply_put_element_setup(PlyFile *, const char *);
extern void ply_put_element(PlyFile *, void *);
extern void ply_put_comment(PlyFile *, const char *);
extern void ply_put_obj_info(PlyFile *, const char *);
extern PlyFile *ply_read(FILE *, int *, char ***);
extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *);
extern PlyProperty **ply_get_element_description(PlyFile *, char *, int*, int*);
extern void ply_get_element_setup( PlyFile *, char *, int, PlyProperty *);
extern void ply_get_property(PlyFile *, char *, PlyProperty *);
extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int);
extern void ply_get_element(PlyFile *, void *);
extern char **ply_get_comments(PlyFile *, int *);
extern char **ply_get_obj_info(PlyFile *, int *);
extern void ply_close(PlyFile *);
extern void ply_get_info(PlyFile *, float *, int *);
extern PlyOtherElems *ply_get_other_element (PlyFile *, char *, int);
extern void ply_describe_other_elements ( PlyFile *, PlyOtherElems *);
extern void ply_put_other_elements (PlyFile *);
extern void ply_free_other_elements (PlyOtherElems *);
extern int equal_strings(const char *, const char *);
#ifdef __cplusplus
}
#endif
#endif /* !__PLY_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,112 @@
/*
typedefs.h
Copyright (c) 2007, Tobias Wolf <twolf@access.unizh.ch>
All rights reserved.
Type definitions for the mesh classes.
*/
/** note, derived from Equalizer LGPL source.*/
#ifndef MESH_TYPEDEFS_H
#define MESH_TYPEDEFS_H
# ifdef WIN32
# include <Winsock2.h>
# include <Windows.h>
# endif
# include <osg/Notify>
# include <cassert>
# define MESHASSERT assert
# define MESHERROR osg::notify(osg::WARN)
# define MESHWARN osg::notify(osg::WARN)
# define MESHINFO osg::notify(osg::INFO)
#ifdef WIN32
typedef int socklen_t;
typedef UINT64 uint64_t;
typedef INT64 int64_t;
typedef UINT32 uint32_t;
typedef INT32 int32_t;
typedef UINT16 uint16_t;
typedef UINT8 uint8_t;
# ifndef HAVE_SSIZE_T
typedef SSIZE_T ssize_t;
# endif
#endif // Win32
#include <exception>
#include <iostream>
#include <string>
namespace ply
{
typedef size_t Index;
// typedef unsigned short ShortIndex;
// mesh exception
struct MeshException : public std::exception
{
explicit MeshException( const std::string& msg ) : _message( msg ) {}
virtual ~MeshException() throw() {}
virtual const char* what() const throw() { return _message.c_str(); }
private:
std::string _message;
};
// null output stream that discards everything written to it
struct NullOStream : std::ostream
{
struct NullStreamBuf : std::streambuf
{
int overflow( int c ) { return traits_type::not_eof( c ); }
} _nullBuf;
NullOStream() : std::ios( &_nullBuf ), std::ostream( &_nullBuf ) {}
};
// wrapper to enable array use where arrays would not be allowed otherwise
template< class T, size_t d >
struct ArrayWrapper
{
T& operator[]( const size_t i )
{
MESHASSERT( i < d );
return data[i];
}
const T& operator[]( const size_t i ) const
{
MESHASSERT( i < d );
return data[i];
}
private:
T data[d];
};
// binary mesh file version, increment if changing the file format
const unsigned short FILE_VERSION ( 0x0114 );
// enumeration for the sort axis
enum Axis
{
AXIS_X,
AXIS_Y,
AXIS_Z
};
}
#endif // MESH_TYPEDEFS_H

View File

@@ -0,0 +1,373 @@
/*
vertexData.cpp
Copyright (c) 2007, Tobias Wolf <twolf@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>
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 )
{
// Initialize the members
_vertices = NULL;
_colors = NULL;
_normals = NULL;
_triangles = NULL;
}
/* Read the vertex and (if available/wanted) color data from the open file. */
void VertexData::readVertices( PlyFile* file, const int nVertices,
const bool readColors )
{
// temporary vertex structure for ply loading
struct _Vertex
{
float x;
float y;
float z;
unsigned char r;
unsigned char g;
unsigned char b;
} 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 },
{ "red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, r ), 0, 0, 0, 0 },
{ "green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, g ), 0, 0, 0, 0 },
{ "blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, b ), 0, 0, 0, 0 }
};
// use all 6 properties when reading colors, only the first 3 otherwise
int limit = readColors ? 6 : 3;
for( int i = 0; i < limit; ++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 read colors allocate space for color array
if( readColors )
{
if(!_colors.valid())
_colors = new osg::Vec4Array;
}
// 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( readColors )
_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 ) );
}
}
/* 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", PLY_INT, PLY_INT, offsetof( _Face, vertices ),
1, PLY_UCHAR, PLY_UCHAR, offsetof( _Face, nVertices ) }
};
ply_get_property( file, "face", &faceProps[0] );
//triangles.clear();
//triangles.reserve( nFaces );
if(!_triangles.valid())
_triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
// read in the faces, asserting that they are only triangles
uint8_t ind1 = _invertFaces ? 2 : 0;
uint8_t ind3 = _invertFaces ? 0 : 2;
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 )
{
free( face.vertices );
throw MeshException( "Error reading PLY file. Encountered a "
"face which does not have three vertices." );
}
// 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 );
}
}
/* 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 = ply_open_for_reading( const_cast< char* >( filename ),
&nPlyElems, &elemNames,
&fileType, &version );
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
for( int i = 0; i < nComments; i++ )
{
if( equal_strings( comments[i], "modified by flipply" ) )
{
_invertFaces = true;
}
}
for( int i = 0; i < nPlyElems; ++i )
{
int nElems;
int nProps;
PlyProperty** props = ply_get_element_description( file, elemNames[i],
&nElems, &nProps );
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" ) )
{
bool hasColors = false;
// 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, "red" ) )
hasColors = true;
if( ignoreColors )
MESHINFO << "Colors in PLY file ignored per request." << endl;
// Read vertices and store in a std::vector array
readVertices( file, nElems, hasColors && !ignoreColors );
// Check whether all vertices are loaded or not
MESHASSERT( _vertices->size() == static_cast< size_t >( nElems ) );
// Check all color elements read or not
if( hasColors && !ignoreColors )
MESHASSERT( _colors->size() == static_cast< size_t >( nElems ) );
}
// 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
MESHASSERT( _triangles->size()/3 == static_cast< size_t >( nElems ) );
result = true;
}
catch( exception& e )
{
MESHERROR << "Unable to read PLY file, an exception occured: "
<< 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());
// If the normals are not calculated calculate the normals for faces
if(!_normals.valid())
_calculateNormals();
// set the normals
geom->setNormalArray(_normals.get());
geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
// Add the premetive set
geom->addPrimitiveSet(_triangles.get());
// if color info is given set the color array
if(_colors.valid())
{
geom->setColorArray(_colors.get());
geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
}
// set flage true to activate the vertex buffer object of drawable
geom->setUseVertexBufferObjects(true);
osg::Geode* geode = new osg::Geode;
geode->addDrawable(geom);
return geode;
}
return NULL;
}
/* 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
}

View File

@@ -0,0 +1,74 @@
/*
vertexData.h
Copyright (c) 2007, Tobias Wolf <twolf@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
class 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:
// 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 bool readColors );
// 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
osg::ref_ptr<osg::Vec3Array> _vertices;
// Color array in osg format
osg::ref_ptr<osg::Vec4Array> _colors;
// Normals in osg format
osg::ref_ptr<osg::Vec3Array> _normals;
// The indices of the faces in premitive set
osg::ref_ptr<osg::DrawElementsUInt> _triangles;
};
}
#endif // MESH_VERTEXDATA_H