diff --git a/src/osgPlugins/ply/CMakeLists.txt b/src/osgPlugins/ply/CMakeLists.txt new file mode 100644 index 000000000..c83bab123 --- /dev/null +++ b/src/osgPlugins/ply/CMakeLists.txt @@ -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) diff --git a/src/osgPlugins/ply/ReaderWriterPLY.cpp b/src/osgPlugins/ply/ReaderWriterPLY.cpp new file mode 100644 index 000000000..b0873056a --- /dev/null +++ b/src/osgPlugins/ply/ReaderWriterPLY.cpp @@ -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 +#include +#include +#include + + +#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; +} diff --git a/src/osgPlugins/ply/ply.h b/src/osgPlugins/ply/ply.h new file mode 100644 index 000000000..1ae2c6afc --- /dev/null +++ b/src/osgPlugins/ply/ply.h @@ -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 +#include + +#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__ */ + diff --git a/src/osgPlugins/ply/plyfile.cpp b/src/osgPlugins/ply/plyfile.cpp new file mode 100644 index 000000000..d1705622d --- /dev/null +++ b/src/osgPlugins/ply/plyfile.cpp @@ -0,0 +1,2686 @@ +/* Copyright (c) 2005-2007, Stefan Eilemann + All rights reserved. + - Cleaned up code for 64 bit, little and big endian support + - Added new ply data types (uint8, float32, int32) + */ + +/* + +The interface routines for reading and writing PLY polygon files. + +Greg Turk, February 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 the floating-point values x,y,z and the three unsigned +chars representing 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. + +*/ + +#include "ply.h" +#include +#include +#include +#include + +#ifdef WIN32 +# ifndef LITTLE_ENDIAN +# define LITTLE_ENDIAN +# endif +#endif + +const char *type_names[] = { + "invalid", + "char", "short", "int", + "uchar", "ushort", "uint", + "float", "double", "float32", "uint8", "int32" +}; + +int ply_type_size[] = { + 0, 1, 2, 4, 1, 2, 4, 4, 8, 4, 1, 4 +}; + +#define NO_OTHER_PROPS -1 + +#define DONT_STORE_PROP 0 +#define STORE_PROP 1 + +#define OTHER_PROP 0 +#define NAMED_PROP 1 + + +/* returns 1 if strings are equal, 0 if not */ +int equal_strings(const char *, const char *); + +/* find an element in a plyfile's list */ +PlyElement *find_element(PlyFile *, const char *); + +/* find a property in an element's list */ +PlyProperty *find_property(PlyElement *, const char *, int *); + +/* write to a file the word describing a PLY file data type */ +void write_scalar_type (FILE *, int); + +/* read a line from a file and break it up into separate words */ +char **get_words(FILE *, int *, char **); + +/* write an item to a file */ +void write_binary_item(PlyFile *, int, unsigned int, double, int); +void write_ascii_item(FILE *, int, unsigned int, double, int); + +/* add information to a PLY file descriptor */ +void add_element(PlyFile *, char **, int); +void add_property(PlyFile *, char **, int); +void add_comment(PlyFile *, char *); +void add_obj_info(PlyFile *, char *); + +/* copy a property */ +void copy_property(PlyProperty *, PlyProperty *); + +/* store a value into where a pointer and a type specify */ +void store_item(char *, int, int, unsigned int, double); + +/* return the value of a stored item */ +void get_stored_item( void *, int, int *, unsigned int *, double *); + +/* return the value stored in an item, given ptr to it and its type */ +double get_item_value(char *, int); + +/* get binary or ascii item and store it according to ptr and type */ +void get_ascii_item(char *, int, int *, unsigned int *, double *); +void get_binary_item(PlyFile *, int, int *, unsigned int *, double *); + +/* get a bunch of elements from a file */ +void ascii_get_element(PlyFile *, char *); +void binary_get_element(PlyFile *, char *); + +/* memory allocation */ +char *my_alloc(int, int, const char *); + +/************************/ +/* Byte-swapping macros */ +/************************/ + +void swap2Bytes( void* ptr ) +{ + unsigned char* bytes = (unsigned char*)ptr; + unsigned short* result = (unsigned short*)ptr; + + *result = (bytes[0]<<8) | bytes[1]; +} + +void swap4Bytes( void* ptr ) +{ + unsigned char* bytes = (unsigned char*)ptr; + unsigned int* result = (unsigned int*)ptr; + + *result = (bytes[0]<<24) | (bytes[1]<<16) | (bytes[2]<<8) | bytes[3]; +} + +void swap8Bytes( void* ptr ) +{ + unsigned char* bytes = (unsigned char*)ptr; + unsigned long long* result = (unsigned long long*)ptr; + + *result = ((unsigned long long)(bytes[0])) << 56 | + ((unsigned long long)(bytes[1])) << 48 | + ((unsigned long long)(bytes[2])) << 40 | + ((unsigned long long)(bytes[3])) << 32 | + ((unsigned long long)(bytes[4])) << 24 | + ((unsigned long long)(bytes[5])) << 16 | + ((unsigned long long)(bytes[6])) << 8 | + bytes[7]; + + +} + +#ifdef LITTLE_ENDIAN +void swap2LE( void* ) {} +void swap2LE( short* ) {} +void swap2LE( unsigned short* ) {} +void swap4LE( void* ) {} +void swap4LE( int* ) {} +void swap4LE( unsigned int* ) {} +void swap4LE( float* ) {} +void swap8LE( void* ) {} +void swap8LE( long long* ) {} +void swap8LE( unsigned long long* ) {} +void swap8LE( double* ) {} + +void swap2BE( void* ptr ) { swap2Bytes(ptr); } +void swap2BE( short* ptr ) { swap2Bytes(ptr); } +void swap2BE( unsigned short* ptr ) { swap2Bytes(ptr); } +void swap4BE( void* ptr ) { swap4Bytes(ptr); } +void swap4BE( int* ptr ) { swap4Bytes(ptr); } +void swap4BE( unsigned int* ptr ) { swap4Bytes(ptr); } +void swap4BE( float* ptr ) { swap4Bytes(ptr); } +void swap8BE( long long* ptr ) { swap8Bytes(ptr); } +void swap8BE( void* ptr ) { swap8Bytes(ptr); } +void swap8BE( unsigned long long* ptr ) { swap8Bytes(ptr); } +void swap8BE( double* ptr ) { swap8Bytes(ptr); } + +#else // LITTLE_ENDIAN + +void swap2LE( void* ptr ) { swap2Bytes(ptr); } +void swap2LE( short* ptr ) { swap2Bytes(ptr); } +void swap2LE( unsigned short* ptr ) { swap2Bytes(ptr); } +void swap4LE( void* ptr ) { swap4Bytes(ptr); } +void swap4LE( int* ptr ) { swap4Bytes(ptr); } +void swap4LE( unsigned int* ptr ) { swap4Bytes(ptr); } +void swap4LE( float* ptr ) { swap4Bytes(ptr); } +void swap8LE( long long* ptr ) { swap8Bytes(ptr); } +void swap8LE( void* ptr ) { swap8Bytes(ptr); } +void swap8LE( unsigned long long* ptr ) { swap8Bytes(ptr); } +void swap8LE( double* ptr ) { swap8Bytes(ptr); } + +void swap2BE( void* ) {} +void swap2BE( short* ) {} +void swap2BE( unsigned short* ) {} +void swap4BE( void* ) {} +void swap4BE( int* ) {} +void swap4BE( unsigned int* ) {} +void swap4BE( float* ) {} +void swap8BE( void* ) {} +void swap8BE( long long* ) {} +void swap8BE( unsigned long long* ) {} +void swap8BE( double* ) {} + +#endif // LITTLE_ENDIAN + + +/*************/ +/* Writing */ +/*************/ + + +/****************************************************************************** +Given a file pointer, get ready to write PLY data to the file. + +Entry: + fp - the given file pointer + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_write( + FILE *fp, + int nelems, + const char **elem_names, + int file_type +) +{ + int i; + PlyFile *plyfile; + PlyElement *elem; + + /* check for NULL file pointer */ + if (fp == NULL) + return (NULL); + + /* create a record for this object */ + + plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); + plyfile->file_type = file_type; + plyfile->num_comments = 0; + plyfile->num_obj_info = 0; + plyfile->nelems = nelems; + plyfile->version = 1.0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + + /* tuck aside the names of the elements */ + + plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems); + for (i = 0; i < nelems; i++) { + elem = (PlyElement *) myalloc (sizeof (PlyElement)); + plyfile->elems[i] = elem; + elem->name = strdup (elem_names[i]); + elem->num = 0; + elem->nprops = 0; + } + + /* return pointer to the file descriptor */ + return (plyfile); +} + + +/****************************************************************************** +Open a polygon file for writing. + +Entry: + filename - name of file to read from + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + version - version number of PLY file + returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_open_for_writing( + char *filename, + int nelems, + const char **elem_names, + int file_type, + float *version +) +{ + PlyFile *plyfile; + char *name; + FILE *fp; + + + /* tack on the extension .ply, if necessary */ + name = (char *) myalloc (sizeof (char) * + (static_cast(strlen (filename)) + 5)); + strcpy (name, filename); + if (strlen (name) < 4 || + strcmp (name + strlen (name) - 4, ".ply") != 0) + strcat (name, ".ply"); + + /* open the file for writing */ + + fp = fopen (name, "wb"); + free (name); //wjs remove memory leak// + if (fp == NULL) { + return (NULL); + } + + /* create the actual PlyFile structure */ + + plyfile = ply_write (fp, nelems, elem_names, file_type); + if (plyfile == NULL) + return (NULL); + + /* say what PLY file version number we're writing */ + *version = plyfile->version; + + /* return pointer to the file descriptor */ + return (plyfile); +} + + +/****************************************************************************** +Describe an element, including its properties and how many will be written +to the file. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + nelems - number of elements of this type to be written + nprops - number of properties contained in the element + prop_list - list of properties +******************************************************************************/ + +void ply_describe_element( + PlyFile *plyfile, + const char *elem_name, + int nelems, + int nprops, + PlyProperty *prop_list +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"ply_describe_element: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; + + /* copy the list of properties */ + + elem->nprops = nprops; + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops); + elem->store_prop = (char *) myalloc (sizeof (char) * nprops); + + for (i = 0; i < nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[i] = prop; + elem->store_prop[i] = NAMED_PROP; + copy_property (prop, &prop_list[i]); + } +} + + +/****************************************************************************** +Describe a property of an element. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + prop - the new property +******************************************************************************/ + +void ply_describe_property( + PlyFile *plyfile, + const char *elem_name, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *elem_prop; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr, "ply_describe_property: can't find element '%s'\n", + elem_name); + return; + } + + /* create room for new property */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + elem->store_prop = (char *) myalloc (sizeof (char)); + elem->nprops = 1; + } + else { + elem->nprops++; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * elem->nprops); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * elem->nprops); + } + + /* copy the new property */ + elem->other_offset = 0; //added by wjs Purify UMR + elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[elem->nprops - 1] = elem_prop; + elem->store_prop[elem->nprops - 1] = NAMED_PROP; + copy_property (elem_prop, prop); +} + + +/****************************************************************************** +Describe what the "other" properties are that are to be stored, and where +they are in an element. +******************************************************************************/ + +void ply_describe_other_properties( + PlyFile *plyfile, + PlyOtherProp *other, + int offset +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element (plyfile, other->name); + if (elem == NULL) { + fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n", + other->name); + return; + } + + /* create room for other properties */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) + myalloc (sizeof (PlyProperty *) * other->nprops); + elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops); + elem->nprops = 0; + } + else { + int newsize; + newsize = elem->nprops + other->nprops; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * newsize); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * newsize); + } + + /* copy the other properties */ + + for (i = 0; i < other->nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, other->props[i]); + elem->props[elem->nprops] = prop; + elem->store_prop[elem->nprops] = OTHER_PROP; + elem->nprops++; + } + + /* save other info about other properties */ + elem->other_size = other->size; + elem->other_offset = offset; +} + + +/****************************************************************************** +State how many of a given element will be written. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + nelems - number of elements of this type to be written +******************************************************************************/ + +void ply_element_count( + PlyFile *plyfile, + const char *elem_name, + int nelems +) +{ + PlyElement *elem; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"ply_element_count: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; +} + + +/****************************************************************************** +Signal that we've described everything a PLY file's header and that the +header should be written to the file. + +Entry: + plyfile - file identifier +******************************************************************************/ + +void ply_header_complete(PlyFile *plyfile) +{ + int i,j; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + + fprintf (fp, "ply\n"); + + switch (plyfile->file_type) { + case PLY_ASCII: + fprintf (fp, "format ascii 1.0\n"); + break; + case PLY_BINARY_BE: + fprintf (fp, "format binary_big_endian 1.0\n"); + break; + case PLY_BINARY_LE: + fprintf (fp, "format binary_little_endian 1.0\n"); + break; + default: + fprintf (stderr, "ply_header_complete: bad file type = %d\n", + plyfile->file_type); + exit (-1); + } + + /* write out the comments */ + + for (i = 0; i < plyfile->num_comments; i++) + fprintf (fp, "comment %s\n", plyfile->comments[i]); + + /* write out object information */ + + for (i = 0; i < plyfile->num_obj_info; i++) + fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]); + + /* write out information about each element */ + + for (i = 0; i < plyfile->nelems; i++) { + + elem = plyfile->elems[i]; + fprintf (fp, "element %s %d\n", elem->name, elem->num); + + /* write out each property */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (prop->is_list) { + fprintf (fp, "property list "); + write_scalar_type (fp, prop->count_external); + fprintf (fp, " "); + write_scalar_type (fp, prop->external_type); + fprintf (fp, " %s\n", prop->name); + } + else { + fprintf (fp, "property "); + write_scalar_type (fp, prop->external_type); + fprintf (fp, " %s\n", prop->name); + } + } + } + + fprintf (fp, "end_header\n"); +} + + +/****************************************************************************** +Specify which elements are going to be written. This should be called +before a call to the routine ply_put_element(). + +Entry: + plyfile - file identifier + elem_name - name of element we're talking about +******************************************************************************/ + +void ply_put_element_setup(PlyFile *plyfile, const char *elem_name) +{ + PlyElement *elem; + + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name); + exit (-1); + } + + plyfile->which_elem = elem; +} + + +/****************************************************************************** +Write an element to the file. This routine assumes that we're +writing the type of element specified in the last call to the routine +ply_put_element_setup(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to the element +******************************************************************************/ + +void ply_put_element(PlyFile *plyfile, void *elem_ptr) +{ + int j, k; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + char *elem_data,*item; + char **item_ptr; + int list_count; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + char **other_ptr; + + elem = plyfile->which_elem; + elem_data = (char *)elem_ptr; + other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset); + + /* write out either to an ascii or binary file */ + + if (plyfile->file_type == PLY_ASCII) { + + /* write an ascii file */ + + /* write out each property of the element */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (elem->store_prop[j] == OTHER_PROP) + elem_data = *other_ptr; + else + elem_data = (char *)elem_ptr; + if (prop->is_list) { + item = elem_data + prop->count_offset; + get_stored_item ((void *) item, prop->count_internal, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->count_external); + list_count = uint_val; + item_ptr = (char **) (elem_data + prop->offset); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for (k = 0; k < list_count; k++) { + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->external_type); + item += item_size; + } + } + else { + item = elem_data + prop->offset; + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->external_type); + } + } + + fprintf (fp, "\n"); + } + else { + + /* write a binary file */ + + /* write out each property of the element */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (elem->store_prop[j] == OTHER_PROP) + elem_data = *other_ptr; + else + elem_data = (char *)elem_ptr; + if (prop->is_list) { + item = elem_data + prop->count_offset; + item_size = ply_type_size[prop->count_internal]; + get_stored_item ((void *) item, prop->count_internal, + &int_val, &uint_val, &double_val); + write_binary_item (plyfile, int_val, uint_val, double_val, + prop->count_external); + list_count = uint_val; + item_ptr = (char **) (elem_data + prop->offset); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for (k = 0; k < list_count; k++) { + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_binary_item (plyfile, int_val, uint_val, double_val, + prop->external_type); + item += item_size; + } + } + else { + item = elem_data + prop->offset; + item_size = ply_type_size[prop->internal_type]; + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_binary_item (plyfile, int_val, uint_val, double_val, + prop->external_type); + } + } + + } +} + + +/****************************************************************************** +Specify a comment that will be written in the header. + +Entry: + plyfile - file identifier + comment - the comment to be written +******************************************************************************/ + +void ply_put_comment(PlyFile *plyfile, const char *comment) +{ + /* (re)allocate space for new comment */ + if (plyfile->num_comments == 0) + { + plyfile->comments = (char **) myalloc (sizeof (char *)); + } + else + { + plyfile->comments = (char **) realloc (plyfile->comments, + sizeof (char *) * (plyfile->num_comments + 1)); + } + + /* add comment to list */ + plyfile->comments[plyfile->num_comments] = strdup (comment); + plyfile->num_comments++; +} + + +/****************************************************************************** +Specify a piece of object information (arbitrary text) that will be written +in the header. + +Entry: + plyfile - file identifier + obj_info - the text information to be written +******************************************************************************/ + +void ply_put_obj_info(PlyFile *plyfile, const char *obj_info) +{ + /* (re)allocate space for new info */ + if (plyfile->num_obj_info == 0) + { + plyfile->obj_info = (char **) myalloc (sizeof (char *)); + } + else + { + plyfile->obj_info = (char **) realloc (plyfile->obj_info, + sizeof (char *) * (plyfile->num_obj_info + 1)); + } + + /* add info to list */ + plyfile->obj_info[plyfile->num_obj_info] = strdup (obj_info); + plyfile->num_obj_info++; +} + + + + + + + +/*************/ +/* Reading */ +/*************/ + + + +/****************************************************************************** +Given a file pointer, get ready to read PLY data from the file. + +Entry: + fp - the given file pointer + +Exit: + nelems - number of elements in object + elem_names - list of element names + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names) +{ + int i,j; + PlyFile *plyfile; + int nwords; + char **words; + char **elist; + PlyElement *elem; + char *orig_line; + + /* check for NULL file pointer */ + if (fp == NULL) + return (NULL); + + /* create record for this object */ + + plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); + plyfile->nelems = 0; + plyfile->comments = NULL; + plyfile->num_comments = 0; + plyfile->obj_info = NULL; + plyfile->num_obj_info = 0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + + /* read and parse the file's header */ + + words = get_words (plyfile->fp, &nwords, &orig_line); + if (!words || !equal_strings (words[0], "ply")) + return (NULL); + + while (words) { + + /* parse words */ + + if (equal_strings (words[0], "format")) { + if (nwords != 3) + return (NULL); + if (equal_strings (words[1], "ascii")) + plyfile->file_type = PLY_ASCII; + else if (equal_strings (words[1], "binary_big_endian")) + plyfile->file_type = PLY_BINARY_BE; + else if (equal_strings (words[1], "binary_little_endian")) + plyfile->file_type = PLY_BINARY_LE; + else + { + free (words); + return (NULL); + } + plyfile->version = atof (words[2]); + } + else if (equal_strings (words[0], "element")) + add_element (plyfile, words, nwords); + else if (equal_strings (words[0], "property")) + add_property (plyfile, words, nwords); + else if (equal_strings (words[0], "comment")) + add_comment (plyfile, orig_line); + else if (equal_strings (words[0], "obj_info")) + add_obj_info (plyfile, orig_line); + else if (equal_strings (words[0], "end_header")) + { + free (words); + break; + } + + /* free up words space */ + free (words); + + words = get_words (plyfile->fp, &nwords, &orig_line); + } + + + /* create tags for each property of each element, to be used */ + /* later to say whether or not to store each property for the user */ + + for (i = 0; i < plyfile->nelems; i++) { + elem = plyfile->elems[i]; + elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops); + for (j = 0; j < elem->nprops; j++) + elem->store_prop[j] = DONT_STORE_PROP; + elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */ + } + + /* set return values about the elements */ + + elist = (char **) myalloc (sizeof (char *) * plyfile->nelems); + for (i = 0; i < plyfile->nelems; i++) + elist[i] = strdup (plyfile->elems[i]->name); + + *elem_names = elist; + *nelems = plyfile->nelems; + + /* return a pointer to the file's information */ + + return (plyfile); +} + + +/****************************************************************************** +Open a polygon file for reading. + +Entry: + filename - name of file to read from + +Exit: + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + version - version number of PLY file + returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_open_for_reading( + char *filename, + int *nelems, + char ***elem_names, + int *file_type, + float *version +) +{ + FILE *fp; + PlyFile *plyfile; + char *name; + + /* tack on the extension .ply, if necessary */ + + name = (char *) myalloc (sizeof (char) * + (static_cast(strlen (filename) + 5))); + strcpy (name, filename); + if (strlen (name) < 4 || + strcmp (name + strlen (name) - 4, ".ply") != 0) + strcat (name, ".ply"); + + /* open the file for reading */ + + fp = fopen (name, "rb"); + free(name); + if (fp == NULL) + return (NULL); + + /* create the PlyFile data structure */ + + plyfile = ply_read (fp, nelems, elem_names); + + /* determine the file type and version */ + + *file_type = plyfile->file_type; + *version = plyfile->version; + + /* return a pointer to the file's information */ + + return (plyfile); +} + + +/****************************************************************************** +Get information about a particular element. + +Entry: + plyfile - file identifier + elem_name - name of element to get information about + +Exit: + nelems - number of elements of this type in the file + nprops - number of properties + returns a list of properties, or NULL if the file doesn't contain that elem +******************************************************************************/ + +PlyProperty **ply_get_element_description( + PlyFile *plyfile, + char *elem_name, + int *nelems, + int *nprops +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + PlyProperty **prop_list; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) + return (NULL); + + *nelems = elem->num; + *nprops = elem->nprops; + + /* make a copy of the element's property list */ + prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops); + for (i = 0; i < elem->nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, elem->props[i]); + prop_list[i] = prop; + } + + /* return this duplicate property list */ + return (prop_list); +} + + +/****************************************************************************** +Specify which properties of an element are to be returned. This should be +called before a call to the routine ply_get_element(). + +Entry: + plyfile - file identifier + elem_name - which element we're talking about + nprops - number of properties + prop_list - list of properties +******************************************************************************/ + +void ply_get_element_setup( PlyFile *plyfile, char *elem_name, int nprops, + PlyProperty *prop_list ) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + int index; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + for (i = 0; i < nprops; i++) + { + /* look for actual property */ + prop = find_property (elem, prop_list[i].name, &index); + if (prop == NULL) + { + fprintf ( stderr, + "Warning: Can't find property '%s' in element '%s'\n", + prop_list[i].name, elem_name ); + continue; + } + + /* store its description */ + prop->internal_type = prop_list[i].internal_type; + prop->offset = prop_list[i].offset; + prop->count_internal = prop_list[i].count_internal; + prop->count_offset = prop_list[i].count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; + } +} + + +/****************************************************************************** +Specify a property of an element that is to be returned. This should be +called (usually multiple times) before a call to the routine ply_get_element(). +This routine should be used in preference to the less flexible old routine +called ply_get_element_setup(). + +Entry: + plyfile - file identifier + elem_name - which element we're talking about + prop - property to add to those that will be returned +******************************************************************************/ + +void ply_get_property( + PlyFile *plyfile, + char *elem_name, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *prop_ptr; + int index; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + + prop_ptr = find_property (elem, prop->name, &index); + if (prop_ptr == NULL) { + 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; +} + + +/****************************************************************************** +Read one element from the file. This routine assumes that we're reading +the type of element specified in the last call to the routine +ply_get_element_setup(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to location where the element information should be put +******************************************************************************/ + +void ply_get_element(PlyFile *plyfile, void *elem_ptr) +{ + if (plyfile->file_type == PLY_ASCII) + ascii_get_element (plyfile, (char *) elem_ptr); + else + binary_get_element (plyfile, (char *) elem_ptr); +} + + +/****************************************************************************** +Extract the comments from the header information of a PLY file. + +Entry: + plyfile - file identifier + +Exit: + num_comments - number of comments returned + returns a pointer to a list of comments +******************************************************************************/ + +char **ply_get_comments(PlyFile *plyfile, int *num_comments) +{ + *num_comments = plyfile->num_comments; + return (plyfile->comments); +} + + +/****************************************************************************** +Extract the object information (arbitrary text) from the header information +of a PLY file. + +Entry: + plyfile - file identifier + +Exit: + num_obj_info - number of lines of text information returned + returns a pointer to a list of object info lines +******************************************************************************/ + +char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info) +{ + *num_obj_info = plyfile->num_obj_info; + return (plyfile->obj_info); +} + + +/****************************************************************************** +Make ready for "other" properties of an element-- those properties that +the user has not explicitly asked for, but that are to be stashed away +in a special structure to be carried along with the element's other +information. + +Entry: + plyfile - file identifier + elem - element for which we want to save away other properties +******************************************************************************/ + +void setup_other_props(PlyFile *, PlyElement *elem) +{ + int i; + PlyProperty *prop; + int size = 0; + int type_size; + + /* Examine each property in decreasing order of size. */ + /* We do this so that all data types will be aligned by */ + /* word, half-word, or whatever within the structure. */ + + for (type_size = 8; type_size > 0; type_size /= 2) { + + /* add up the space taken by each property, and save this information */ + /* away in the property descriptor */ + + for (i = 0; i < elem->nprops; i++) { + + /* don't bother with properties we've been asked to store explicitly */ + if (elem->store_prop[i]) + continue; + + prop = elem->props[i]; + + /* internal types will be same as external */ + prop->internal_type = prop->external_type; + prop->count_internal = prop->count_external; + + /* check list case */ + if (prop->is_list) { + + /* pointer to list */ + if (type_size == sizeof (void *)) { + prop->offset = size; + size += sizeof (void *); /* always use size of a pointer here */ + } + + /* count of number of list elements */ + if (type_size == ply_type_size[prop->count_external]) { + prop->count_offset = size; + size += ply_type_size[prop->count_external]; + } + } + /* not list */ + else if (type_size == ply_type_size[prop->external_type]) { + prop->offset = size; + size += ply_type_size[prop->external_type]; + } + } + + } + + /* save the size for the other_props structure */ + elem->other_size = size; +} + + +/****************************************************************************** +Specify that we want the "other" properties of an element to be tucked +away within the user's structure. The user needn't be concerned for how +these properties are stored. + +Entry: + plyfile - file identifier + elem_name - name of element that we want to store other_props in + offset - offset to where other_props will be stored inside user's structure + +Exit: + returns pointer to structure containing description of other_props +******************************************************************************/ + +PlyOtherProp *ply_get_other_properties( + PlyFile *plyfile, + char *elem_name, + int offset +) +{ + int i; + PlyElement *elem; + PlyOtherProp *other; + PlyProperty *prop; + int nprops; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n", + elem_name); + return (NULL); + } + + /* remember that this is the "current" element */ + plyfile->which_elem = elem; + + /* save the offset to where to store the other_props */ + elem->other_offset = offset; + + /* place the appropriate pointers, etc. in the element's property list */ + setup_other_props (plyfile, elem); + + /* create structure for describing other_props */ + other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp)); + other->name = strdup (elem_name); +#if 0 + if (elem->other_offset == NO_OTHER_PROPS) { + other->size = 0; + other->props = NULL; + other->nprops = 0; + return (other); + } +#endif + other->size = elem->other_size; + other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops); + + /* save descriptions of each "other" property */ + nprops = 0; + for (i = 0; i < elem->nprops; i++) { + if (elem->store_prop[i]) + continue; + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, elem->props[i]); + other->props[nprops] = prop; + nprops++; + } + other->nprops = nprops; + +#if 1 + /* set other_offset pointer appropriately if there are NO other properties */ + if (other->nprops == 0) { + elem->other_offset = NO_OTHER_PROPS; + } +#endif + + /* return structure */ + return (other); +} + + + + +/*************************/ +/* Other Element Stuff */ +/*************************/ + + + + +/****************************************************************************** +Grab all the data for an element that a user does not want to explicitly +read in. + +Entry: + plyfile - pointer to file + elem_name - name of element whose data is to be read in + elem_count - number of instances of this element stored in the file + +Exit: + returns pointer to ALL the "other" element data for this PLY file +******************************************************************************/ + +PlyOtherElems *ply_get_other_element ( + PlyFile *plyfile, + char *elem_name, + int elem_count +) +{ + int i; + PlyElement *elem; + PlyOtherElems *other_elems; + OtherElem *other; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf (stderr, + "ply_get_other_element: can't find element '%s'\n", elem_name); + exit (-1); + } + + /* create room for the new "other" element, initializing the */ + /* other data structure if necessary */ + + if (plyfile->other_elems == NULL) { + plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems)); + other_elems = plyfile->other_elems; + other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem)); + other = &(other_elems->other_list[0]); + other_elems->num_elems = 1; + } + else { + other_elems = plyfile->other_elems; + other_elems->other_list = (OtherElem *) realloc (other_elems->other_list, + sizeof (OtherElem) * other_elems->num_elems + 1); + other = &(other_elems->other_list[other_elems->num_elems]); + other_elems->num_elems++; + } + + /* count of element instances in file */ + other->elem_count = elem_count; + + /* save name of element */ + other->elem_name = strdup (elem_name); + + /* create a list to hold all the current elements */ + other->other_data = (OtherData **) + malloc (sizeof (OtherData *) * other->elem_count); + + /* set up for getting elements */ + other->other_props = ply_get_other_properties (plyfile, elem_name, + offsetof(OtherData,other_props)); + + /* grab all these elements */ + for (i = 0; i < other->elem_count; i++) { + /* grab and element from the file */ + other->other_data[i] = (OtherData *) malloc (sizeof (OtherData)); + ply_get_element (plyfile, (void *) other->other_data[i]); + } + + /* return pointer to the other elements data */ + return (other_elems); +} + + +/****************************************************************************** +Pass along a pointer to "other" elements that we want to save in a given +PLY file. These other elements were presumably read from another PLY file. + +Entry: + plyfile - file pointer in which to store this other element info + other_elems - info about other elements that we want to store +******************************************************************************/ + +void ply_describe_other_elements ( + PlyFile *plyfile, + PlyOtherElems *other_elems +) +{ + int i; + OtherElem *other; + + /* ignore this call if there is no other element */ + if (other_elems == NULL) + return; + + /* save pointer to this information */ + plyfile->other_elems = other_elems; + + /* describe the other properties of this element */ + + for (i = 0; i < other_elems->num_elems; i++) { + other = &(other_elems->other_list[i]); + ply_element_count (plyfile, other->elem_name, other->elem_count); + ply_describe_other_properties (plyfile, other->other_props, + offsetof(OtherData,other_props)); + } +} + + +/****************************************************************************** +Write out the "other" elements specified for this PLY file. + +Entry: + plyfile - pointer to PLY file to write out other elements for +******************************************************************************/ + +void ply_put_other_elements (PlyFile *plyfile) +{ + int i,j; + OtherElem *other; + + /* make sure we have other elements to write */ + if (plyfile->other_elems == NULL) + return; + + /* write out the data for each "other" element */ + + for (i = 0; i < plyfile->other_elems->num_elems; i++) { + + other = &(plyfile->other_elems->other_list[i]); + ply_put_element_setup (plyfile, other->elem_name); + + /* write out each instance of the current element */ + for (j = 0; j < other->elem_count; j++) + ply_put_element (plyfile, (void *) other->other_data[j]); + } +} + + +/****************************************************************************** +Free up storage used by an "other" elements data structure. + +Entry: + other_elems - data structure to free up +******************************************************************************/ + +void ply_free_other_elements (PlyOtherElems *) +{ + +} + + + +/*******************/ +/* Miscellaneous */ +/*******************/ + + + +/****************************************************************************** +Close a PLY file. + +Entry: + plyfile - identifier of file to close +******************************************************************************/ + +void ply_close(PlyFile *plyfile) +{ + // Changed by Will Schroeder. Old stuff leaked like a sieve. + + /* free up memory associated with the PLY file */ + fclose (plyfile->fp); + + int i, j; + PlyElement *elem; + for (i=0; inelems; i++) + { + elem = plyfile->elems[i]; + if ( elem->name ) {free(elem->name);} + for (j=0; jnprops; j++) + { + if ( elem->props[j]->name ) {free(const_cast(elem->props[j]->name));} + free (elem->props[j]); + } + free (elem->props); + free (elem->store_prop); + free (elem); + } + free(plyfile->elems); + + for (i=0; inum_comments; i++) + { + free (plyfile->comments[i]); + } + free (plyfile->comments); + + for (i=0; inum_obj_info; i++) + { + free (plyfile->obj_info[i]); + } + free (plyfile->obj_info); + + free (plyfile); +} + + +/****************************************************************************** +Get version number and file type of a PlyFile. + +Entry: + ply - pointer to PLY file + +Exit: + version - version of the file + file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE +******************************************************************************/ + +void ply_get_info(PlyFile *ply, float *version, int *file_type) +{ + if (ply == NULL) + return; + + *version = ply->version; + *file_type = ply->file_type; +} + + +/****************************************************************************** +Compare two strings. Returns 1 if they are the same, 0 if not. +******************************************************************************/ + +int equal_strings(const char *s1, const char *s2) +{ + while (*s1 && *s2) + if (*s1++ != *s2++) + return (0); + + if (*s1 != *s2) + return (0); + else + return (1); +} + + +/****************************************************************************** +Find an element from the element list of a given PLY object. + +Entry: + plyfile - file id for PLY file + element - name of element we're looking for + +Exit: + returns the element, or NULL if not found +******************************************************************************/ + +PlyElement *find_element(PlyFile *plyfile, const char *element) +{ + int i; + + for (i = 0; i < plyfile->nelems; i++) + if (equal_strings (element, plyfile->elems[i]->name)) + return (plyfile->elems[i]); + + return (NULL); +} + + +/****************************************************************************** +Find a property in the list of properties of a given element. + +Entry: + elem - pointer to element in which we want to find the property + prop_name - name of property to find + +Exit: + index - index to position in list + returns a pointer to the property, or NULL if not found +******************************************************************************/ + +PlyProperty *find_property(PlyElement *elem, const char *prop_name, int *index) +{ + int i; + + for( i = 0; i < elem->nprops; i++) + if (equal_strings (prop_name, elem->props[i]->name)) + { + *index = i; + return (elem->props[i]); + } + + *index = -1; + return (NULL); +} + + +/****************************************************************************** +Read an element from an ascii file. + +Entry: + plyfile - file identifier + elem_ptr - pointer to element +******************************************************************************/ + +void ascii_get_element(PlyFile *plyfile, char *elem_ptr) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + char **words; + int nwords; + int which_word; + char *elem_data,*item=0; + char *item_ptr; + int item_size=0; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *orig_line; + char *other_data=0; + int other_flag; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if (elem->other_offset != NO_OTHER_PROPS) { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) myalloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) (elem_ptr + elem->other_offset); + *ptr = other_data; + } + else + other_flag = 0; + + /* read in the element */ + + words = get_words (plyfile->fp, &nwords, &orig_line); + if (words == NULL) { + fprintf (stderr, "ply_get_element: unexpected end of file\n"); + exit (-1); + } + + which_word = 0; + + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + store_it = (elem->store_prop[j] | other_flag); + + /* store either in the user's structure or in other_props */ + if (elem->store_prop[j]) + elem_data = elem_ptr; + else + elem_data = other_data; + + if (prop->is_list) { /* a list */ + + /* get and store the number of items in the list */ + get_ascii_item (words[which_word++], prop->count_external, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->count_offset; + store_item(item, prop->count_internal, int_val, uint_val, double_val); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + item_size = ply_type_size[prop->internal_type]; + store_array = (char **) (elem_data + prop->offset); + + if (list_count == 0) { + if (store_it) + *store_array = NULL; + } + else { + if (store_it) { + item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for (k = 0; k < list_count; k++) { + get_ascii_item (words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + store_item (item, prop->internal_type, + int_val, uint_val, double_val); + item += item_size; + } + } + } + + } + else { /* not a list */ + get_ascii_item (words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->offset; + store_item (item, prop->internal_type, int_val, uint_val, double_val); + } + } + + } + + free (words); +} + + +/****************************************************************************** +Read an element from a binary file. + +Entry: + plyfile - file identifier + elem_ptr - pointer to an element +******************************************************************************/ + +void binary_get_element(PlyFile *plyfile, char *elem_ptr) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + //FILE *fp = plyfile->fp; + char *elem_data,*item=0; + char *item_ptr; + int item_size=0; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *other_data=0; + int other_flag; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if (elem->other_offset != NO_OTHER_PROPS) { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) myalloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) (elem_ptr + elem->other_offset); + *ptr = other_data; + } + else + other_flag = 0; + + /* read in a number of elements */ + + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + store_it = (elem->store_prop[j] | other_flag); + + /* store either in the user's structure or in other_props */ + if (elem->store_prop[j]) + elem_data = elem_ptr; + else + elem_data = other_data; + + if (prop->is_list) { /* a list */ + + /* get and store the number of items in the list */ + get_binary_item (plyfile, prop->count_external, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->count_offset; + store_item(item, prop->count_internal, int_val, uint_val, double_val); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + /* The "if" was added by Afra Zomorodian 8/22/95 + * so that zipper won't crash reading plies that have additional + * properties. + */ + if (store_it) { + item_size = ply_type_size[prop->internal_type]; + } + store_array = (char **) (elem_data + prop->offset); + if (list_count == 0) { + if (store_it) + *store_array = NULL; + } + else { + if (store_it) { + item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for (k = 0; k < list_count; k++) { + get_binary_item (plyfile, prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + store_item (item, prop->internal_type, + int_val, uint_val, double_val); + item += item_size; + } + } + } + + } + else { /* not a list */ + get_binary_item (plyfile, prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->offset; + store_item (item, prop->internal_type, int_val, uint_val, double_val); + } + } + + } +} + + +/****************************************************************************** +Write to a file the word that represents a PLY data type. + +Entry: + fp - file pointer + code - code for type +******************************************************************************/ + +void write_scalar_type (FILE *fp, int code) +{ + /* make sure this is a valid code */ + + if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) { + fprintf (stderr, "write_scalar_type: bad data code = %d\n", code); + exit (-1); + } + + /* write the code to a file */ + + fprintf (fp, "%s", type_names[code]); +} + + +/****************************************************************************** +Get a text line from a file and break it up into words. + +IMPORTANT: The calling routine call "free" on the returned pointer once +finished with it. + +Entry: + fp - file to read from + +Exit: + nwords - number of words returned + orig_line - the original line of characters + returns a list of words from the line, or NULL if end-of-file +******************************************************************************/ + +char **get_words(FILE *fp, int *nwords, char **orig_line) +{ +#define BIG_STRING 4096 + static char str[BIG_STRING]; + static char str_copy[BIG_STRING]; + char **words; + int max_words = 10; + int num_words = 0; + char *ptr,*ptr2; + char *result; + + /* read in a line */ + result = fgets (str, BIG_STRING, fp); + if (result == NULL) { + *nwords = 0; + *orig_line = NULL; + return (NULL); + } + + words = (char **) myalloc (sizeof (char *) * max_words); + + /* convert line-feed and tabs into spaces */ + /* (this guarentees that there will be a space before the */ + /* null character at the end of the string) */ + + str[BIG_STRING-2] = ' '; + str[BIG_STRING-1] = '\0'; + + for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) { + *ptr2 = *ptr; + if (*ptr == '\t') { + *ptr = ' '; + *ptr2 = ' '; + } + else if (*ptr == '\n') { + *ptr = ' '; + *ptr2 = '\0'; + break; + } + } + + /* find the words in the line */ + + ptr = str; + while (*ptr != '\0') { + + /* jump over leading spaces */ + while (*ptr == ' ') + ptr++; + + /* break if we reach the end */ + if (*ptr == '\0') + break; + + /* save pointer to beginning of word */ + if (num_words >= max_words) { + max_words += 10; + words = (char **) realloc (words, sizeof (char *) * max_words); + } + words[num_words++] = ptr; + + /* jump over non-spaces */ + while (*ptr != ' ') + ptr++; + + /* place a null character here to mark the end of the word */ + *ptr++ = '\0'; + } + + /* return the list of words */ + *nwords = num_words; + *orig_line = str_copy; + return (words); +} + + +/****************************************************************************** +Return the value of an item, given a pointer to it and its type. + +Entry: + item - pointer to item + type - data type that "item" points to + +Exit: + returns a double-precision float that contains the value of the item +******************************************************************************/ + +double get_item_value(char *item, int type) +{ + unsigned char *puchar; + char *pchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + int int_value; + unsigned int uint_value; + double double_value; + + switch (type) { + case PLY_CHAR: + pchar = (char *) item; + int_value = *pchar; + return ((double) int_value); + case PLY_UCHAR: + case PLY_UINT8: + puchar = (unsigned char *) item; + int_value = *puchar; + return ((double) int_value); + case PLY_SHORT: + pshort = (short int *) item; + int_value = *pshort; + return ((double) int_value); + case PLY_USHORT: + pushort = (unsigned short int *) item; + int_value = *pushort; + return ((double) int_value); + case PLY_INT: + case PLY_INT32: + pint = (int *) item; + int_value = *pint; + return ((double) int_value); + case PLY_UINT: + puint = (unsigned int *) item; + uint_value = *puint; + return ((double) uint_value); + case PLY_FLOAT: + case PLY_FLOAT32: + pfloat = (float *) item; + double_value = *pfloat; + return (double_value); + case PLY_DOUBLE: + pdouble = (double *) item; + double_value = *pdouble; + return (double_value); + } + fprintf (stderr, "get_item_value: bad type = %d\n", type); + return 0; +} + + +/****************************************************************************** +Write out an item to a file as raw binary bytes. + +Entry: + fp - file to write to + int_val - integer version of item + uint_val - unsigned integer version of item + double_val - double-precision float version of item + type - data type to write out +******************************************************************************/ + +void write_binary_item(PlyFile *plyfile, + int int_val, + unsigned int uint_val, + double double_val, + int type +) +{ + FILE *fp = plyfile->fp; + unsigned char uchar_val; + char char_val; + unsigned short ushort_val; + short short_val; + float float_val; + + switch (type) { + case PLY_CHAR: + char_val = int_val; + fwrite (&char_val, 1, 1, fp); + break; + case PLY_SHORT: + short_val = int_val; + if( plyfile->file_type == PLY_BINARY_BE ) + swap2BE(&short_val); + else + swap2LE(&short_val); + fwrite (&short_val, 2, 1, fp); + break; + case PLY_INT: + case PLY_INT32: + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap4BE(&int_val); + } + else + { + swap4LE(&int_val); + } + fwrite (&int_val, 4, 1, fp); + break; + case PLY_UCHAR: + case PLY_UINT8: + uchar_val = uint_val; + fwrite (&uchar_val, 1, 1, fp); + break; + case PLY_USHORT: + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap2BE(&ushort_val); + } + else + { + swap2LE(&ushort_val); + } + ushort_val = uint_val; + fwrite (&ushort_val, 2, 1, fp); + break; + case PLY_UINT: + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap4BE(&uint_val); + } + else + { + swap4LE(&uint_val); + } + fwrite (&uint_val, 4, 1, fp); + break; + case PLY_FLOAT: + case PLY_FLOAT32: + float_val = double_val; + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap4BE(&float_val); + } + else + { + swap4LE(&float_val); + } + fwrite (&float_val, 4, 1, fp); + break; + case PLY_DOUBLE: + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap8BE(&double_val); + } + else + { + swap8LE(&double_val); + } + fwrite (&double_val, 8, 1, fp); + break; + default: + fprintf (stderr, "write_binary_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as ascii characters. + +Entry: + fp - file to write to + int_val - integer version of item + uint_val - unsigned integer version of item + double_val - double-precision float version of item + type - data type to write out +******************************************************************************/ + +void write_ascii_item( + FILE *fp, + int int_val, + unsigned int uint_val, + double double_val, + int type +) +{ + switch (type) { + case PLY_CHAR: + case PLY_SHORT: + case PLY_INT: + case PLY_INT32: + fprintf (fp, "%d ", int_val); + break; + case PLY_UCHAR: + case PLY_UINT8: + case PLY_USHORT: + case PLY_UINT: + fprintf (fp, "%u ", uint_val); + break; + case PLY_FLOAT: + case PLY_FLOAT32: + case PLY_DOUBLE: + fprintf (fp, "%g ", double_val); + break; + default: + fprintf (stderr, "write_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + +/****************************************************************************** +Get the value of an item that is in memory, and place the result +into an integer, an unsigned integer and a double. + +Entry: + ptr - pointer to the item + type - data type supposedly in the item + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_stored_item( + void *ptr, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + switch (type) { + case PLY_CHAR: + *int_val = *((char *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UCHAR: + case PLY_UINT8: + *uint_val = *((unsigned char *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_SHORT: + *int_val = *((short int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_USHORT: + *uint_val = *((unsigned short int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_INT: + case PLY_INT32: + *int_val = *((int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UINT: + *uint_val = *((unsigned int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_FLOAT: + case PLY_FLOAT32: + *double_val = *((float *) ptr); + *int_val = (int) *double_val; + *uint_val = (unsigned int) *double_val; + break; + case PLY_DOUBLE: + *double_val = *((double *) ptr); + *int_val = (int) *double_val; + *uint_val = (unsigned int) *double_val; + break; + default: + fprintf (stderr, "get_stored_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Get the value of an item from a binary file, and place the result +into an integer, an unsigned integer and a double. + +Entry: + fp - file to get item from + type - data type supposedly in the word + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_binary_item( + PlyFile *plyfile, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + char c[8]; + void *ptr; + + ptr = (void *) c; + + switch (type) { + case PLY_CHAR: + fread (ptr, 1, 1, plyfile->fp); + *int_val = *((char *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UCHAR: + case PLY_UINT8: + fread (ptr, 1, 1, plyfile->fp); + *uint_val = *((unsigned char *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_SHORT: + fread (ptr, 2, 1, plyfile->fp); + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap2BE(ptr); + } + else + { + swap2LE(ptr); + } + *int_val = *((short int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_USHORT: + fread (ptr, 2, 1, plyfile->fp); + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap2BE(ptr); + } + else + { + swap2LE(ptr); + } + *uint_val = *((unsigned short int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_INT: + case PLY_INT32: + fread (ptr, 4, 1, plyfile->fp); + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap4BE(ptr); + } + else + { + swap4LE(ptr); + } + *int_val = *((int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UINT: + fread (ptr, 4, 1, plyfile->fp); + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap4BE(ptr); + } + else + { + swap4LE(ptr); + } + *uint_val = *((unsigned int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_FLOAT: + case PLY_FLOAT32: + fread (ptr, 4, 1, plyfile->fp); + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap4BE(ptr); + } + else + { + swap4LE(ptr); + } + *double_val = *((float *) ptr); + *int_val = (int) *double_val; + *uint_val = (unsigned int) *double_val; + break; + case PLY_DOUBLE: + fread (ptr, 8, 1, plyfile->fp); + if( plyfile->file_type == PLY_BINARY_BE ) + { + swap8BE(ptr); + } + else + { + swap8LE(ptr); + } + *double_val = *((double *) ptr); + *int_val = (int) *double_val; + *uint_val = (unsigned int) *double_val; + break; + default: + fprintf (stderr, "get_binary_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Extract the value of an item from an ascii word, and place the result +into an integer, an unsigned integer and a double. + +Entry: + word - word to extract value from + type - data type supposedly in the word + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_ascii_item( + char *word, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + switch (type) { + case PLY_CHAR: + case PLY_UCHAR: + case PLY_UINT8: + case PLY_SHORT: + case PLY_USHORT: + case PLY_INT: + case PLY_INT32: + *int_val = atoi (word); + *uint_val = *int_val; + *double_val = *int_val; + break; + + case PLY_UINT: + *uint_val = strtoul (word, (char **) NULL, 10); + *int_val = *uint_val; + *double_val = *uint_val; + break; + + case PLY_FLOAT: + case PLY_FLOAT32: + case PLY_DOUBLE: + *double_val = atof (word); + *int_val = (int) *double_val; + *uint_val = (unsigned int) *double_val; + break; + + default: + fprintf (stderr, "get_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Store a value into a place being pointed to, guided by a data type. + +Entry: + item - place to store value + type - data type + int_val - integer version of value + uint_val - unsigned integer version of value + double_val - double version of value + +Exit: + item - pointer to stored value +******************************************************************************/ + +void store_item ( + char *item, + int type, + int int_val, + unsigned int uint_val, + double double_val +) +{ + unsigned char *puchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + + switch (type) { + case PLY_CHAR: + *item = int_val; + break; + case PLY_UCHAR: + case PLY_UINT8: + puchar = (unsigned char *) item; + *puchar = uint_val; + break; + case PLY_SHORT: + pshort = (short *) item; + *pshort = int_val; + break; + case PLY_USHORT: + pushort = (unsigned short *) item; + *pushort = uint_val; + break; + case PLY_INT: + case PLY_INT32: + pint = (int *) item; + *pint = int_val; + break; + case PLY_UINT: + puint = (unsigned int *) item; + *puint = uint_val; + break; + case PLY_FLOAT: + case PLY_FLOAT32: + pfloat = (float *) item; + *pfloat = double_val; + break; + case PLY_DOUBLE: + pdouble = (double *) item; + *pdouble = double_val; + break; + default: + fprintf (stderr, "store_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Add an element to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + words - list of words describing the element + nwords - number of words in the list +******************************************************************************/ + +void add_element (PlyFile *plyfile, char **words, int) +{ + PlyElement *elem; + + /* create the new element */ + elem = (PlyElement *) myalloc (sizeof (PlyElement)); + elem->name = strdup (words[1]); + elem->num = atoi (words[2]); + elem->nprops = 0; + + /* make room for new element in the object's list of elements */ + if (plyfile->nelems == 0) + plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *)); + else + plyfile->elems = (PlyElement **) realloc (plyfile->elems, + sizeof (PlyElement *) * (plyfile->nelems + 1)); + + /* add the new element to the object's list */ + plyfile->elems[plyfile->nelems] = elem; + plyfile->nelems++; +} + + +/****************************************************************************** +Return the type of a property, given the name of the property. + +Entry: + name - name of property type + +Exit: + returns integer code for property, or 0 if not found +******************************************************************************/ + +int get_prop_type(char *type_name) +{ + int i; + + for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++) + if (equal_strings (type_name, type_names[i])) + return (i); + + /* if we get here, we didn't find the type */ + return (0); +} + + +/****************************************************************************** +Add a property to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + words - list of words describing the property + nwords - number of words in the list +******************************************************************************/ + +void add_property (PlyFile *plyfile, char **words, int ) +{ + PlyProperty *prop; + PlyElement *elem; + + /* create the new property */ + + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + + if (equal_strings (words[1], "list")) { /* is a list */ + prop->count_external = get_prop_type (words[2]); + prop->external_type = get_prop_type (words[3]); + prop->name = strdup (words[4]); + prop->is_list = 1; + } + else { /* not a list */ + prop->external_type = get_prop_type (words[1]); + prop->name = strdup (words[2]); + prop->is_list = 0; + } + + /* add this property to the list of properties of the current element */ + + elem = plyfile->elems[plyfile->nelems - 1]; + + if (elem->nprops == 0) + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + else + elem->props = (PlyProperty **) realloc (elem->props, + sizeof (PlyProperty *) * (elem->nprops + 1)); + + elem->props[elem->nprops] = prop; + elem->nprops++; +} + + +/****************************************************************************** +Add a comment to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + line - line containing comment +******************************************************************************/ + +void add_comment (PlyFile *plyfile, char *line) +{ + int i; + + /* skip over "comment" and leading spaces and tabs */ + i = 7; + while (line[i] == ' ' || line[i] == '\t') + i++; + + ply_put_comment (plyfile, &line[i]); +} + + +/****************************************************************************** +Add a some object information to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + line - line containing text info +******************************************************************************/ + +void add_obj_info (PlyFile *plyfile, char *line) +{ + int i; + + /* skip over "obj_info" and leading spaces and tabs */ + i = 8; + while (line[i] == ' ' || line[i] == '\t') + i++; + + ply_put_obj_info (plyfile, &line[i]); +} + + +/****************************************************************************** +Copy a property. +******************************************************************************/ + +void copy_property(PlyProperty *dest, PlyProperty *src) +{ + dest->name = strdup (src->name); + dest->external_type = src->external_type; + dest->internal_type = src->internal_type; + dest->offset = src->offset; + + dest->is_list = src->is_list; + dest->count_external = src->count_external; + dest->count_internal = src->count_internal; + dest->count_offset = src->count_offset; +} + + +/****************************************************************************** +Allocate some memory. + +Entry: + size - amount of memory requested (in bytes) + lnum - line number from which memory was requested + fname - file name from which memory was requested +******************************************************************************/ + +char *my_alloc(int size, int lnum, const char *fname) +{ + char *ptr; + + ptr = (char *) malloc (size); + + if (ptr == 0) + fprintf( stderr, "Memory allocation bombed on line %d in %s\n", + lnum, fname); + + return (ptr); +} + diff --git a/src/osgPlugins/ply/typedefs.h b/src/osgPlugins/ply/typedefs.h new file mode 100644 index 000000000..b5c01b236 --- /dev/null +++ b/src/osgPlugins/ply/typedefs.h @@ -0,0 +1,112 @@ +/* + typedefs.h + Copyright (c) 2007, Tobias Wolf + 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 +# include +# endif + +# include +# include +# 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 +#include +#include + +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 diff --git a/src/osgPlugins/ply/vertexData.cpp b/src/osgPlugins/ply/vertexData.cpp new file mode 100644 index 000000000..66ae3d302 --- /dev/null +++ b/src/osgPlugins/ply/vertexData.cpp @@ -0,0 +1,373 @@ +/* + vertexData.cpp + Copyright (c) 2007, Tobias Wolf + All rights reserved. + + Implementation of the VertexData class. +*/ + +/** note, derived from Equalizer LGPL source.*/ + +#include "typedefs.h" + +#include "vertexData.h" +#include "ply.h" +#include +#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 ) +{ + // 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 +} + diff --git a/src/osgPlugins/ply/vertexData.h b/src/osgPlugins/ply/vertexData.h new file mode 100644 index 000000000..173ecefd6 --- /dev/null +++ b/src/osgPlugins/ply/vertexData.h @@ -0,0 +1,74 @@ +/* + vertexData.h + Copyright (c) 2007, Tobias Wolf + All rights reserved. + + Header file of the VertexData class. +*/ + +/** note, derived from Equalizer LGPL source.*/ + + +#ifndef MESH_VERTEXDATA_H +#define MESH_VERTEXDATA_H + + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +//! +//! \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 _vertices; + // Color array in osg format + osg::ref_ptr _colors; + // Normals in osg format + osg::ref_ptr _normals; + // The indices of the faces in premitive set + osg::ref_ptr _triangles; + }; +} + + +#endif // MESH_VERTEXDATA_H