Index: /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter.vcproj
===================================================================
--- /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter.vcproj	(revision 3342)
+++ /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter.vcproj	(revision 3357)
@@ -156,5 +156,5 @@
 				AdditionalLibraryDirectories="libs\Zlib\lib"
 				IgnoreDefaultLibraryNames="libCMT"
-				GenerateDebugInformation="false"
+				GenerateDebugInformation="true"
 				SubSystem="1"
 				LargeAddressAware="2"
@@ -214,4 +214,12 @@
 			</File>
 			<File
+				RelativePath=".\Converter\PlyConverter.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\Converter\rply.c"
+				>
+			</File>
+			<File
 				RelativePath=".\Converter\SimpleTri.cpp"
 				>
@@ -240,4 +248,12 @@
 			</File>
 			<File
+				RelativePath=".\Converter\PlyConverter.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Converter\rply.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Converter\SimpleTri.h"
 				>
Index: /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/PlyConverter.h
===================================================================
--- /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/PlyConverter.h	(revision 3357)
+++ /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/PlyConverter.h	(revision 3357)
@@ -0,0 +1,69 @@
+#ifndef _PLYCONVERTER_H
+#define _PLYCONVERTER_H
+
+#include "SimpleVec.h"
+#include <string>
+#include <vector>
+#include <map>
+
+
+static std::string model_path("data/city/model/");
+
+
+typedef std::vector<SimpleVec> VertexArray;
+typedef std::pair<float, float> Texcoord;
+typedef std::vector<SimpleVec> TexcoordArray;
+typedef std::map<std::string, int> TextureTable;
+typedef std::vector<std::string> TextureArray;
+
+
+class ogzstream;
+
+
+
+/** Converts obj format into objects readable by our format
+*/
+class PlyConverter
+{
+public:
+
+	~PlyConverter();
+
+	bool Convert(const std::string &inputFilename, 
+		         const std::string &outputFilename);
+	             // const std::string textureFilename) const;
+
+
+protected:
+
+	void LoadShape(const VertexArray &faceVertices,
+		           const VertexArray &faceNormals,
+				   const std::vector<Texcoord> &faceTexcoords
+				   );
+
+	struct Geometry
+	{
+		VertexArray mVertices;
+		VertexArray mNormals;
+		TexcoordArray mTexcoords;
+	};
+
+	typedef std::vector<Geometry *> GeometryArray;
+
+	void WriteGeometry(ogzstream &str, Geometry *geom);
+
+	bool ReadFile(const std::string &inputFilename);
+	bool WriteFile(const std::string &outputFilename);
+
+
+	TextureTable mTextureTable;
+	
+	TextureArray mTextures;
+	GeometryArray mGeometry;
+
+	int mNumShapes;
+};
+
+
+
+#endif
Index: /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/main.cpp
===================================================================
--- /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/main.cpp	(revision 3342)
+++ /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/main.cpp	(revision 3357)
@@ -1,3 +1,4 @@
-#include "ObjConverter.h"
+//#include "ObjConverter.h"
+#include "PlyConverter.h"
 #include <iostream>
 #include <time.h>
@@ -11,9 +12,10 @@
 
 	//ObjConverter2 converter;
-	ObjConverter converter;
+	//ObjConverter converter;
+	PlyConverter converter;
 
 	cout << "converting obj to dem format" << endl;
 #if 1
-	if (!converter.LoadMaterials(model_path + argv[3]))
+	/*if (!converter.LoadMaterials(model_path + argv[3]))
 	{
 		cerr << "loading materials failed" << endl;
@@ -21,5 +23,5 @@
 		std::cin.get();
 		exit(0);
-	}
+	}*/
 
 	if (!converter.Convert(model_path + argv[1], model_path + argv[2]))
@@ -58,5 +60,5 @@
 
 	cout << "conversion successful" << endl;
-	//cout << "press any key" << std::cin.get();
+	cout << "press any key" << std::cin.get();
 
 	return 0;
Index: /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/rply.c
===================================================================
--- /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/rply.c	(revision 3357)
+++ /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/rply.c	(revision 3357)
@@ -0,0 +1,1497 @@
+/* ----------------------------------------------------------------------
+ * RPly library, read/write PLY files
+ * Diego Nehab, Princeton University
+ * http://www.cs.princeton.edu/~diego/professional/rply
+ *
+ * This library is distributed under the MIT License. See notice
+ * at the end of this file.
+ * ---------------------------------------------------------------------- */
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+#include <limits.h>
+#include <float.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "rply.h"
+
+/* ----------------------------------------------------------------------
+ * Constants 
+ * ---------------------------------------------------------------------- */
+#define WORDSIZE 256
+#define LINESIZE 1024
+#define BUFFERSIZE (8*1024)
+
+typedef enum e_ply_io_mode_ {
+    PLY_READ, 
+    PLY_WRITE
+} e_ply_io_mode;
+
+static const char *const ply_storage_mode_list[] = {
+    "binary_big_endian", "binary_little_endian", "ascii", NULL
+};     /* order matches e_ply_storage_mode enum */
+
+static const char *const ply_type_list[] = {
+    "int8", "uint8", "int16", "uint16", 
+    "int32", "uint32", "float32", "float64",
+    "char", "uchar", "short", "ushort", 
+    "int", "uint", "float", "double",
+    "list", NULL
+};     /* order matches e_ply_type enum */
+
+/* ----------------------------------------------------------------------
+ * Property reading callback argument
+ *
+ * element: name of element being processed
+ * property: name of property being processed
+ * nelements: number of elements of this kind in file
+ * instance_index: index current element of this kind being processed
+ * length: number of values in current list (or 1 for scalars)
+ * value_index: index of current value int this list (or 0 for scalars)
+ * value: value of property
+ * pdata/idata: user data defined with ply_set_cb
+ *
+ * Returns handle to ply file if succesful, NULL otherwise.
+ * ---------------------------------------------------------------------- */
+typedef struct t_ply_argument_ {
+    p_ply_element element;
+    long instance_index;
+    p_ply_property property;
+    long length, value_index;
+    double value;
+    void *pdata;
+    long idata;
+} t_ply_argument;
+
+/* ----------------------------------------------------------------------
+ * Property information
+ *
+ * name: name of this property
+ * type: type of this property (list or type of scalar value)
+ * length_type, value_type: type of list property count and values
+ * read_cb: function to be called when this property is called
+ *
+ * Returns 1 if should continue processing file, 0 if should abort.
+ * ---------------------------------------------------------------------- */
+typedef struct t_ply_property_ {
+    char name[WORDSIZE];
+    e_ply_type type, value_type, length_type;
+    p_ply_read_cb read_cb;
+    void *pdata;
+    long idata;
+} t_ply_property; 
+
+/* ----------------------------------------------------------------------
+ * Element information
+ *
+ * name: name of this property
+ * ninstances: number of elements of this type in file
+ * property: property descriptions for this element
+ * nproperty: number of properties in this element
+ *
+ * Returns 1 if should continue processing file, 0 if should abort.
+ * ---------------------------------------------------------------------- */
+typedef struct t_ply_element_ {
+    char name[WORDSIZE];
+    long ninstances;
+    p_ply_property property;
+    long nproperties;
+} t_ply_element;
+
+/* ----------------------------------------------------------------------
+ * Input/output driver
+ *
+ * Depending on file mode, different functions are used to read/write 
+ * property fields. The drivers make it transparent to read/write in ascii, 
+ * big endian or little endian cases.
+ * ---------------------------------------------------------------------- */
+typedef int (*p_ply_ihandler)(p_ply ply, double *value);
+typedef int (*p_ply_ichunk)(p_ply ply, void *anydata, size_t size);
+typedef struct t_ply_idriver_ {
+    p_ply_ihandler ihandler[16];
+    p_ply_ichunk ichunk;
+    const char *name;
+} t_ply_idriver;
+typedef t_ply_idriver *p_ply_idriver;
+
+typedef int (*p_ply_ohandler)(p_ply ply, double value);
+typedef int (*p_ply_ochunk)(p_ply ply, void *anydata, size_t size);
+typedef struct t_ply_odriver_ {
+    p_ply_ohandler ohandler[16];
+    p_ply_ochunk ochunk;
+    const char *name;
+} t_ply_odriver;
+typedef t_ply_odriver *p_ply_odriver;
+
+/* ----------------------------------------------------------------------
+ * Ply file handle. 
+ *
+ * io_mode: read or write (from e_ply_io_mode)
+ * storage_mode: mode of file associated with handle (from e_ply_storage_mode)
+ * element: elements description for this file
+ * nelement: number of different elements in file
+ * comment: comments for this file
+ * ncomments: number of comments in file
+ * obj_info: obj_info items for this file
+ * nobj_infos: number of obj_info items in file
+ * fp: file pointer associated with ply file
+ * c: last character read from ply file
+ * buffer: last word/chunck of data read from ply file
+ * buffer_first, buffer_last: interval of untouched good data in buffer
+ * buffer_token: start of parsed token (line or word) in buffer
+ * idriver, odriver: input driver used to get property fields from file 
+ * argument: storage space for callback arguments
+ * welement, wproperty: element/property type being written
+ * winstance_index: index of instance of current element being written
+ * wvalue_index: index of list property value being written 
+ * wlength: number of values in list property being written
+ * error_cb: callback for error messages
+ * ---------------------------------------------------------------------- */
+typedef struct t_ply_ {
+    e_ply_io_mode io_mode;
+    e_ply_storage_mode storage_mode;
+    p_ply_element element;
+    long nelements;
+    char *comment;
+    long ncomments;
+    char *obj_info;
+    long nobj_infos;
+    FILE *fp;
+    int c;
+    char buffer[BUFFERSIZE];
+    size_t buffer_first, buffer_token, buffer_last;
+    p_ply_idriver idriver;
+    p_ply_odriver odriver;
+    t_ply_argument argument;
+    long welement, wproperty;
+    long winstance_index, wvalue_index, wlength;
+    p_ply_error_cb error_cb;
+} t_ply;
+
+/* ----------------------------------------------------------------------
+ * I/O functions and drivers
+ * ---------------------------------------------------------------------- */
+static t_ply_idriver ply_idriver_ascii;
+static t_ply_idriver ply_idriver_binary;
+static t_ply_idriver ply_idriver_binary_reverse;
+static t_ply_odriver ply_odriver_ascii;
+static t_ply_odriver ply_odriver_binary;
+static t_ply_odriver ply_odriver_binary_reverse;
+
+static int ply_read_word(p_ply ply);
+static int ply_check_word(p_ply ply);
+static int ply_read_line(p_ply ply);
+static int ply_check_line(p_ply ply);
+static int ply_read_chunk(p_ply ply, void *anybuffer, size_t size);
+static int ply_read_chunk_reverse(p_ply ply, void *anybuffer, size_t size);
+static int ply_write_chunk(p_ply ply, void *anybuffer, size_t size);
+static int ply_write_chunk_reverse(p_ply ply, void *anybuffer, size_t size);
+static void ply_reverse(void *anydata, size_t size);
+
+/* ----------------------------------------------------------------------
+ * String functions
+ * ---------------------------------------------------------------------- */
+static int ply_find_string(const char *item, const char* const list[]);
+static p_ply_element ply_find_element(p_ply ply, const char *name);
+static p_ply_property ply_find_property(p_ply_element element, 
+        const char *name);
+
+/* ----------------------------------------------------------------------
+ * Header parsing
+ * ---------------------------------------------------------------------- */
+static int ply_read_header_format(p_ply ply);
+static int ply_read_header_comment(p_ply ply);
+static int ply_read_header_obj_info(p_ply ply);
+static int ply_read_header_property(p_ply ply);
+static int ply_read_header_element(p_ply ply);
+
+/* ----------------------------------------------------------------------
+ * Error handling
+ * ---------------------------------------------------------------------- */
+static void ply_error_cb(const char *message);
+static void ply_error(p_ply ply, const char *fmt, ...);
+
+/* ----------------------------------------------------------------------
+ * Memory allocation and initialization
+ * ---------------------------------------------------------------------- */
+static void ply_init(p_ply ply);
+static void ply_element_init(p_ply_element element);
+static void ply_property_init(p_ply_property property);
+static p_ply ply_alloc(void);
+static p_ply_element ply_grow_element(p_ply ply);
+static p_ply_property ply_grow_property(p_ply ply, p_ply_element element);
+static void *ply_grow_array(p_ply ply, void **pointer, long *nmemb, long size);
+
+/* ----------------------------------------------------------------------
+ * Special functions
+ * ---------------------------------------------------------------------- */
+static e_ply_storage_mode ply_arch_endian(void);
+static int ply_type_check(void); 
+
+/* ----------------------------------------------------------------------
+ * Auxiliary read functions
+ * ---------------------------------------------------------------------- */
+static int ply_read_element(p_ply ply, p_ply_element element, 
+        p_ply_argument argument);
+static int ply_read_property(p_ply ply, p_ply_element element, 
+        p_ply_property property, p_ply_argument argument);
+static int ply_read_list_property(p_ply ply, p_ply_element element, 
+        p_ply_property property, p_ply_argument argument);
+static int ply_read_scalar_property(p_ply ply, p_ply_element element, 
+        p_ply_property property, p_ply_argument argument);
+
+
+/* ----------------------------------------------------------------------
+ * Buffer support functions
+ * ---------------------------------------------------------------------- */
+/* pointers to tokenized word and line in buffer */
+#define BWORD(p) (p->buffer + p->buffer_token)
+#define BLINE(p) (p->buffer + p->buffer_token)
+
+/* pointer to start of untouched bytes in buffer */
+#define BFIRST(p) (p->buffer + p->buffer_first) 
+
+/* number of bytes untouched in buffer */
+#define BSIZE(p) (p->buffer_last - p->buffer_first) 
+
+/* consumes data from buffer */
+#define BSKIP(p, s) (p->buffer_first += s)
+
+/* refills the buffer */
+static int BREFILL(p_ply ply) {
+    /* move untouched data to beginning of buffer */
+    size_t size = BSIZE(ply);
+    memmove(ply->buffer, BFIRST(ply), size);
+    ply->buffer_last = size;
+    ply->buffer_first = ply->buffer_token = 0;
+    /* fill remaining with new data */
+    size = fread(ply->buffer+size, 1, BUFFERSIZE-size-1, ply->fp);
+    /* place sentinel so we can use str* functions with buffer */
+    ply->buffer[BUFFERSIZE-1] = '\0';
+    /* check if read failed */
+    if (size <= 0) return 0;
+    /* increase size to account for new data */
+    ply->buffer_last += size;
+    return 1;
+}
+
+/* ----------------------------------------------------------------------
+ * Exported functions
+ * ---------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------
+ * Read support functions
+ * ---------------------------------------------------------------------- */
+p_ply ply_open(const char *name, p_ply_error_cb error_cb) {
+    char magic[5] = "    ";
+    FILE *fp = NULL; 
+    p_ply ply = NULL;
+    if (error_cb == NULL) error_cb = ply_error_cb;
+    if (!ply_type_check()) {
+        error_cb("Incompatible type system");
+        return NULL;
+    }
+    assert(name);
+    fp = fopen(name, "rb");
+    if (!fp) {
+        error_cb("Unable to open file");
+        return NULL;
+    }
+    if (fread(magic, 1, 4, fp) < 4) {
+        error_cb("Error reading from file");
+        fclose(fp);
+        return NULL;
+    }
+    if (strcmp(magic, "ply\n")) {
+        fclose(fp);
+        error_cb("Not a PLY file. Expected magic number 'ply\\n'");
+        return NULL;
+    }
+    ply = ply_alloc();
+    if (!ply) {
+        error_cb("Out of memory");
+        fclose(fp);
+        return NULL;
+    }
+    ply->fp = fp;
+    ply->io_mode = PLY_READ;
+    ply->error_cb = error_cb;
+    return ply;
+}
+
+int ply_read_header(p_ply ply) {
+    assert(ply && ply->fp && ply->io_mode == PLY_READ);
+    if (!ply_read_word(ply)) return 0;
+    /* parse file format */
+    if (!ply_read_header_format(ply)) {
+        ply_error(ply, "Invalid file format");
+        return 0;
+    }
+    /* parse elements, comments or obj_infos until the end of header */
+    while (strcmp(BWORD(ply), "end_header")) {
+        if (!ply_read_header_comment(ply) && 
+                !ply_read_header_element(ply) && 
+                !ply_read_header_obj_info(ply)) {
+            ply_error(ply, "Unexpected token '%s'", BWORD(ply));
+            return 0;
+        }
+    }
+    return 1;
+}
+
+long ply_set_read_cb(p_ply ply, const char *element_name, 
+        const char* property_name, p_ply_read_cb read_cb, 
+        void *pdata, long idata) {
+    p_ply_element element = NULL; 
+    p_ply_property property = NULL;
+    assert(ply && element_name && property_name);
+    element = ply_find_element(ply, element_name);
+    if (!element) return 0;
+    property = ply_find_property(element, property_name);
+    if (!property) return 0;
+    property->read_cb = read_cb;
+    property->pdata = pdata;
+    property->idata = idata;
+    return (int) element->ninstances;
+}
+
+int ply_read(p_ply ply) {
+    long i;
+    p_ply_argument argument;
+    assert(ply && ply->fp && ply->io_mode == PLY_READ);
+    argument = &ply->argument;
+    /* for each element type */
+    for (i = 0; i < ply->nelements; i++) {
+        p_ply_element element = &ply->element[i];
+        argument->element = element;
+        if (!ply_read_element(ply, element, argument))
+            return 0;
+    }
+    return 1;
+}
+
+/* ----------------------------------------------------------------------
+ * Write support functions
+ * ---------------------------------------------------------------------- */
+p_ply ply_create(const char *name, e_ply_storage_mode storage_mode, 
+        p_ply_error_cb error_cb) {
+    FILE *fp = NULL;
+    p_ply ply = NULL;
+    if (error_cb == NULL) error_cb = ply_error_cb;
+    if (!ply_type_check()) {
+        error_cb("Incompatible type system");
+        return NULL;
+    }
+    assert(name && storage_mode <= PLY_DEFAULT);
+    fp = fopen(name, "wb");
+    if (!fp) {
+        error_cb("Unable to create file");
+        return NULL;
+    }
+    ply = ply_alloc();
+    if (!ply) {
+        fclose(fp);
+        error_cb("Out of memory");
+        return NULL;
+    }
+    ply->io_mode = PLY_WRITE;
+    if (storage_mode == PLY_DEFAULT) storage_mode = ply_arch_endian();
+    if (storage_mode == PLY_ASCII) ply->odriver = &ply_odriver_ascii;
+    else if (storage_mode == ply_arch_endian()) 
+        ply->odriver = &ply_odriver_binary;
+    else ply->odriver = &ply_odriver_binary_reverse;
+    ply->storage_mode = storage_mode;
+    ply->fp = fp;
+    ply->error_cb = error_cb;
+    return ply;
+}
+
+int ply_add_element(p_ply ply, const char *name, long ninstances) {
+    p_ply_element element = NULL;
+    assert(ply && ply->fp && ply->io_mode == PLY_WRITE);
+    assert(name && strlen(name) < WORDSIZE && ninstances >= 0);
+    if (strlen(name) >= WORDSIZE || ninstances < 0) {
+        ply_error(ply, "Invalid arguments");
+        return 0;
+    }
+    element = ply_grow_element(ply);
+    if (!element) return 0;
+    strcpy(element->name, name);
+    element->ninstances = ninstances;
+    return 1;
+}
+
+int ply_add_scalar_property(p_ply ply, const char *name, e_ply_type type) {
+    p_ply_element element = NULL;
+    p_ply_property property = NULL;
+    assert(ply && ply->fp && ply->io_mode == PLY_WRITE);
+    assert(name && strlen(name) < WORDSIZE);
+    assert(type < PLY_LIST);
+    if (strlen(name) >= WORDSIZE || type >= PLY_LIST) {
+        ply_error(ply, "Invalid arguments");
+        return 0;
+    }
+    element = &ply->element[ply->nelements-1];
+    property = ply_grow_property(ply, element);
+    if (!property) return 0;
+    strcpy(property->name, name);
+    property->type = type;
+    return 1;
+}
+
+int ply_add_list_property(p_ply ply, const char *name, 
+        e_ply_type length_type, e_ply_type value_type) {
+    p_ply_element element = NULL;
+    p_ply_property property = NULL;
+    assert(ply && ply->fp && ply->io_mode == PLY_WRITE);
+    assert(name && strlen(name) < WORDSIZE);
+    if (strlen(name) >= WORDSIZE) {
+        ply_error(ply, "Invalid arguments");
+        return 0;
+    }
+    assert(length_type < PLY_LIST);
+    assert(value_type < PLY_LIST);
+    if (length_type >= PLY_LIST || value_type >= PLY_LIST) {
+        ply_error(ply, "Invalid arguments");
+        return 0;
+    }
+    element = &ply->element[ply->nelements-1];
+    property = ply_grow_property(ply, element);
+    if (!property) return 0;
+    strcpy(property->name, name);
+    property->type = PLY_LIST;
+    property->length_type = length_type;
+    property->value_type = value_type;
+    return 1;
+}
+
+int ply_add_property(p_ply ply, const char *name, e_ply_type type,
+        e_ply_type length_type, e_ply_type value_type) {
+    if (type == PLY_LIST) 
+        return ply_add_list_property(ply, name, length_type, value_type);
+    else 
+        return ply_add_scalar_property(ply, name, type);
+}
+
+int ply_add_comment(p_ply ply, const char *comment) {
+    char *new_comment = NULL;
+    assert(ply && comment && strlen(comment) < LINESIZE);
+    if (!comment || strlen(comment) >= LINESIZE) {
+        ply_error(ply, "Invalid arguments");
+        return 0;
+    }
+    new_comment = (char *) ply_grow_array(ply, (void **) &ply->comment,
+            &ply->ncomments, LINESIZE);
+    if (!new_comment) return 0;
+    strcpy(new_comment, comment);
+    return 1;
+}
+
+int ply_add_obj_info(p_ply ply, const char *obj_info) {
+    char *new_obj_info = NULL;
+    assert(ply && obj_info && strlen(obj_info) < LINESIZE);
+    if (!obj_info || strlen(obj_info) >= LINESIZE) {
+        ply_error(ply, "Invalid arguments");
+        return 0;
+    }
+    new_obj_info = (char *) ply_grow_array(ply, (void **) &ply->obj_info,
+            &ply->nobj_infos, LINESIZE);
+    if (!new_obj_info) return 0;
+    strcpy(new_obj_info, obj_info);
+    return 1;
+}
+
+int ply_write_header(p_ply ply) {
+    long i, j;
+    assert(ply && ply->fp && ply->io_mode == PLY_WRITE);
+    assert(ply->element || ply->nelements == 0); 
+    assert(!ply->element || ply->nelements > 0); 
+    if (fprintf(ply->fp, "ply\nformat %s 1.0\n", 
+                ply_storage_mode_list[ply->storage_mode]) <= 0) goto error;
+    for (i = 0; i < ply->ncomments; i++)
+        if (fprintf(ply->fp, "comment %s\n", ply->comment + LINESIZE*i) <= 0)
+            goto error;
+    for (i = 0; i < ply->nobj_infos; i++)
+        if (fprintf(ply->fp, "obj_info %s\n", ply->obj_info + LINESIZE*i) <= 0)
+            goto error;
+    for (i = 0; i < ply->nelements; i++) {
+        p_ply_element element = &ply->element[i];
+        assert(element->property || element->nproperties == 0); 
+        assert(!element->property || element->nproperties > 0); 
+        if (fprintf(ply->fp, "element %s %ld\n", element->name, 
+                    element->ninstances) <= 0) goto error;
+        for (j = 0; j < element->nproperties; j++) {
+            p_ply_property property = &element->property[j];
+            if (property->type == PLY_LIST) {
+                if (fprintf(ply->fp, "property list %s %s %s\n", 
+                            ply_type_list[property->length_type],
+                            ply_type_list[property->value_type],
+                            property->name) <= 0) goto error;
+            } else {
+                if (fprintf(ply->fp, "property %s %s\n", 
+                            ply_type_list[property->type],
+                            property->name) <= 0) goto error;
+            }
+        }
+    }
+    return fprintf(ply->fp, "end_header\n") > 0;
+error:
+    ply_error(ply, "Error writing to file");
+    return 0;
+}
+
+int ply_write(p_ply ply, double value) {
+    p_ply_element element = NULL;
+    p_ply_property property = NULL;
+    int type = -1;
+    int breakafter = 0;
+    if (ply->welement > ply->nelements) return 0;
+    element = &ply->element[ply->welement];
+    if (ply->wproperty > element->nproperties) return 0;
+    property = &element->property[ply->wproperty];
+    if (property->type == PLY_LIST) {
+        if (ply->wvalue_index == 0) {
+            type = property->length_type;
+            ply->wlength = (long) value;
+        } else type = property->value_type;
+    } else {
+        type = property->type;
+        ply->wlength = 0;
+    }
+    if (!ply->odriver->ohandler[type](ply, value)) {
+        ply_error(ply, "Failed writing %s of %s %d (%s: %s)", 
+                    property->name, element->name, 
+                    ply->winstance_index, 
+                    ply->odriver->name, ply_type_list[type]);
+        return 0;
+    }
+    ply->wvalue_index++;
+    if (ply->wvalue_index > ply->wlength) {
+        ply->wvalue_index = 0;
+        ply->wproperty++;
+    }
+    if (ply->wproperty >= element->nproperties) {
+        ply->wproperty = 0;
+        ply->winstance_index++;
+        if (ply->storage_mode == PLY_ASCII) breakafter = 1;
+    }
+    if (ply->winstance_index >= element->ninstances) {
+        ply->winstance_index = 0;
+        ply->welement++;
+    }
+    return !breakafter || putc('\n', ply->fp) > 0;
+}
+
+int ply_close(p_ply ply) {
+    long i;
+    assert(ply && ply->fp);
+    assert(ply->element || ply->nelements == 0);
+    assert(!ply->element || ply->nelements > 0);
+    /* write last chunk to file */
+    if (ply->io_mode == PLY_WRITE && 
+      fwrite(ply->buffer, 1, ply->buffer_last, ply->fp) < ply->buffer_last) {
+        ply_error(ply, "Error closing up");
+        return 0;
+    }
+    fclose(ply->fp);
+    /* free all memory used by handle */
+    if (ply->element) {
+        for (i = 0; i < ply->nelements; i++) {
+            p_ply_element element = &ply->element[i];
+            if (element->property) free(element->property);
+        }
+        free(ply->element);
+    }
+    if (ply->obj_info) free(ply->obj_info);
+    if (ply->comment) free(ply->comment);
+    free(ply);
+    return 1;
+}
+
+/* ----------------------------------------------------------------------
+ * Query support functions
+ * ---------------------------------------------------------------------- */
+p_ply_element ply_get_next_element(p_ply ply, 
+        p_ply_element last) {
+    assert(ply);
+    if (!last) return ply->element;
+    last++;
+    if (last < ply->element + ply->nelements) return last;
+    else return NULL;
+}
+
+int ply_get_element_info(p_ply_element element, const char** name,
+        long *ninstances) {
+    assert(element);
+    if (name) *name = element->name;
+    if (ninstances) *ninstances = (long) element->ninstances;
+    return 1;
+}
+
+p_ply_property ply_get_next_property(p_ply_element element, 
+        p_ply_property last) {
+    assert(element);
+    if (!last) return element->property;
+    last++;
+    if (last < element->property + element->nproperties) return last;
+    else return NULL;
+}
+
+int ply_get_property_info(p_ply_property property, const char** name,
+        e_ply_type *type, e_ply_type *length_type, e_ply_type *value_type) {
+    assert(property);
+    if (name) *name = property->name;
+    if (type) *type = property->type;
+    if (length_type) *length_type = property->length_type;
+    if (value_type) *value_type = property->value_type;
+    return 1;
+
+}
+
+const char *ply_get_next_comment(p_ply ply, const char *last) {
+    assert(ply);
+    if (!last) return ply->comment; 
+    last += LINESIZE;
+    if (last < ply->comment + LINESIZE*ply->ncomments) return last;
+    else return NULL;
+}
+
+const char *ply_get_next_obj_info(p_ply ply, const char *last) {
+    assert(ply);
+    if (!last) return ply->obj_info; 
+    last += LINESIZE;
+    if (last < ply->obj_info + LINESIZE*ply->nobj_infos) return last;
+    else return NULL;
+}
+
+/* ----------------------------------------------------------------------
+ * Callback argument support functions 
+ * ---------------------------------------------------------------------- */
+int ply_get_argument_element(p_ply_argument argument, 
+        p_ply_element *element, long *instance_index) {
+    assert(argument);
+    if (!argument) return 0;
+    if (element) *element = argument->element;
+    if (instance_index) *instance_index = argument->instance_index;
+    return 1;
+}
+
+int ply_get_argument_property(p_ply_argument argument, 
+        p_ply_property *property, long *length, long *value_index) {
+    assert(argument);
+    if (!argument) return 0;
+    if (property) *property = argument->property;
+    if (length) *length = argument->length;
+    if (value_index) *value_index = argument->value_index;
+    return 1;
+}
+
+int ply_get_argument_user_data(p_ply_argument argument, void **pdata, 
+        long *idata) {
+    assert(argument);
+    if (!argument) return 0;
+    if (pdata) *pdata = argument->pdata;
+    if (idata) *idata = argument->idata;
+    return 1;
+}
+
+double ply_get_argument_value(p_ply_argument argument) {
+    assert(argument);
+    if (!argument) return 0.0;
+    return argument->value;
+}
+
+/* ----------------------------------------------------------------------
+ * Internal functions
+ * ---------------------------------------------------------------------- */
+static int ply_read_list_property(p_ply ply, p_ply_element element, 
+        p_ply_property property, p_ply_argument argument) {
+    int l;
+    p_ply_read_cb read_cb = property->read_cb;
+    p_ply_ihandler *driver = ply->idriver->ihandler; 
+    /* get list length */
+    p_ply_ihandler handler = driver[property->length_type];
+    double length;
+    if (!handler(ply, &length)) {
+        ply_error(ply, "Error reading '%s' of '%s' number %d",
+                property->name, element->name, argument->instance_index);
+        return 0;
+    }
+    /* invoke callback to pass length in value field */
+    argument->length = (long) length;
+    argument->value_index = -1;
+    argument->value = length;
+    if (read_cb && !read_cb(argument)) {
+        ply_error(ply, "Aborted by user");
+        return 0;
+    }
+    /* read list values */
+    handler = driver[property->value_type];
+    /* for each value in list */
+    for (l = 0; l < (long) length; l++) {
+        /* read value from file */
+        argument->value_index = l;
+        if (!handler(ply, &argument->value)) {
+            ply_error(ply, "Error reading value number %d of '%s' of "
+                    "'%s' number %d", l+1, property->name, 
+                    element->name, argument->instance_index);
+            return 0;
+        }
+        /* invoke callback to pass value */
+        if (read_cb && !read_cb(argument)) {
+            ply_error(ply, "Aborted by user");
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static int ply_read_scalar_property(p_ply ply, p_ply_element element, 
+        p_ply_property property, p_ply_argument argument) {
+    p_ply_read_cb read_cb = property->read_cb;
+    p_ply_ihandler *driver = ply->idriver->ihandler; 
+    p_ply_ihandler handler = driver[property->type];
+    argument->length = 1;
+    argument->value_index = 0;
+    if (!handler(ply, &argument->value)) {
+        ply_error(ply, "Error reading '%s' of '%s' number %d",
+                property->name, element->name, argument->instance_index);
+        return 0;
+    }
+    if (read_cb && !read_cb(argument)) {
+        ply_error(ply, "Aborted by user");
+        return 0;
+    }
+    return 1;
+}
+
+static int ply_read_property(p_ply ply, p_ply_element element, 
+        p_ply_property property, p_ply_argument argument) {
+    if (property->type == PLY_LIST) 
+        return ply_read_list_property(ply, element, property, argument);
+    else 
+        return ply_read_scalar_property(ply, element, property, argument);
+}
+
+static int ply_read_element(p_ply ply, p_ply_element element, 
+        p_ply_argument argument) {
+    long j, k;
+    /* for each element of this type */
+    for (j = 0; j < element->ninstances; j++) {
+        argument->instance_index = j;
+        /* for each property */
+        for (k = 0; k < element->nproperties; k++) {
+            p_ply_property property = &element->property[k];
+            argument->property = property;
+            argument->pdata = property->pdata;
+            argument->idata = property->idata;
+            if (!ply_read_property(ply, element, property, argument))
+                return 0;
+        }
+    }
+    return 1;
+}
+
+static int ply_find_string(const char *item, const char* const list[]) {
+    int i;
+    assert(item && list);
+    for (i = 0; list[i]; i++) 
+        if (!strcmp(list[i], item)) return i;
+    return -1;
+}
+
+static p_ply_element ply_find_element(p_ply ply, const char *name) {
+    p_ply_element element;
+    int i, nelements;
+    assert(ply && name); 
+    element = ply->element;
+    nelements = ply->nelements;
+    assert(element || nelements == 0); 
+    assert(!element || nelements > 0); 
+    for (i = 0; i < nelements; i++) 
+        if (!strcmp(element[i].name, name)) return &element[i];
+    return NULL;
+}
+
+static p_ply_property ply_find_property(p_ply_element element, 
+        const char *name) {
+    p_ply_property property;
+    int i, nproperties;
+    assert(element && name); 
+    property = element->property;
+    nproperties = element->nproperties;
+    assert(property || nproperties == 0); 
+    assert(!property || nproperties > 0); 
+    for (i = 0; i < nproperties; i++) 
+        if (!strcmp(property[i].name, name)) return &property[i];
+    return NULL;
+}
+
+static int ply_check_word(p_ply ply) {
+    if (strlen(BLINE(ply)) >= WORDSIZE) {
+        ply_error(ply, "Word too long");
+        return 0;
+    }
+    return 1;
+}
+
+static int ply_read_word(p_ply ply) {
+    size_t t = 0;
+    assert(ply && ply->fp && ply->io_mode == PLY_READ);
+    /* skip leading blanks */
+    while (1) {
+        t = strspn(BFIRST(ply), " \n\r\t");
+        /* check if all buffer was made of blanks */
+        if (t >= BSIZE(ply)) {
+            if (!BREFILL(ply)) {
+                ply_error(ply, "Unexpected end of file");
+                return 0;
+            }
+        } else break; 
+    } 
+    BSKIP(ply, t); 
+    /* look for a space after the current word */
+    t = strcspn(BFIRST(ply), " \n\r\t");
+    /* if we didn't reach the end of the buffer, we are done */
+    if (t < BSIZE(ply)) {
+        ply->buffer_token = ply->buffer_first;
+        BSKIP(ply, t);
+        *BFIRST(ply) = '\0';
+        BSKIP(ply, 1);
+        return ply_check_word(ply);
+    }
+    /* otherwise, try to refill buffer */
+    if (!BREFILL(ply)) {
+        ply_error(ply, "Unexpected end of file");
+        return 0;
+    }
+    /* keep looking from where we left */
+    t += strcspn(BFIRST(ply) + t, " \n\r\t");
+    /* check if the token is too large for our buffer */
+    if (t >= BSIZE(ply)) {
+        ply_error(ply, "Token too large");
+        return 0;
+    }
+    /* we are done */
+    ply->buffer_token = ply->buffer_first;
+    BSKIP(ply, t);
+    *BFIRST(ply) = '\0';
+    BSKIP(ply, 1);
+    return ply_check_word(ply);
+}
+
+static int ply_check_line(p_ply ply) {
+    if (strlen(BLINE(ply)) >= LINESIZE) {
+        ply_error(ply, "Line too long");
+        return 0;
+    }
+    return 1;
+}
+
+static int ply_read_line(p_ply ply) {
+    const char *end = NULL;
+    assert(ply && ply->fp && ply->io_mode == PLY_READ);
+    /* look for a end of line */
+    end = strchr(BFIRST(ply), '\n');
+    /* if we didn't reach the end of the buffer, we are done */
+    if (end) {
+        ply->buffer_token = ply->buffer_first;
+        BSKIP(ply, end - BFIRST(ply));
+        *BFIRST(ply) = '\0';
+        BSKIP(ply, 1);
+        return ply_check_line(ply);
+    } else {
+        end = ply->buffer + BSIZE(ply); 
+        /* otherwise, try to refill buffer */
+        if (!BREFILL(ply)) {
+            ply_error(ply, "Unexpected end of file");
+            return 0;
+        }
+    }
+    /* keep looking from where we left */
+    end = strchr(end, '\n');
+    /* check if the token is too large for our buffer */
+    if (!end) {
+        ply_error(ply, "Token too large");
+        return 0;
+    }
+    /* we are done */
+    ply->buffer_token = ply->buffer_first;
+    BSKIP(ply, end - BFIRST(ply));
+    *BFIRST(ply) = '\0';
+    BSKIP(ply, 1);
+    return ply_check_line(ply);
+}
+
+static int ply_read_chunk(p_ply ply, void *anybuffer, size_t size) {
+    char *buffer = (char *) anybuffer;
+    size_t i = 0;
+    assert(ply && ply->fp && ply->io_mode == PLY_READ);
+    assert(ply->buffer_first <= ply->buffer_last);
+    while (i < size) {
+        if (ply->buffer_first < ply->buffer_last) {
+            buffer[i] = ply->buffer[ply->buffer_first];
+            ply->buffer_first++;
+            i++;
+        } else {
+            ply->buffer_first = 0;
+            ply->buffer_last = fread(ply->buffer, 1, BUFFERSIZE, ply->fp);
+            if (ply->buffer_last <= 0) return 0;
+        }
+    }
+    return 1;
+}
+
+static int ply_write_chunk(p_ply ply, void *anybuffer, size_t size) {
+    char *buffer = (char *) anybuffer;
+    size_t i = 0;
+    assert(ply && ply->fp && ply->io_mode == PLY_WRITE);
+    assert(ply->buffer_last <= BUFFERSIZE);
+    while (i < size) {
+        if (ply->buffer_last < BUFFERSIZE) {
+            ply->buffer[ply->buffer_last] = buffer[i];
+            ply->buffer_last++;
+            i++;
+        } else {
+            ply->buffer_last = 0;
+            if (fwrite(ply->buffer, 1, BUFFERSIZE, ply->fp) < BUFFERSIZE)
+                return 0;
+        }
+    }
+    return 1;
+}
+
+static int ply_write_chunk_reverse(p_ply ply, void *anybuffer, size_t size) {
+    int ret = 0;
+    ply_reverse(anybuffer, size);
+    ret = ply_write_chunk(ply, anybuffer, size);
+    ply_reverse(anybuffer, size);
+    return ret;
+}
+
+static int ply_read_chunk_reverse(p_ply ply, void *anybuffer, size_t size) {
+    if (!ply_read_chunk(ply, anybuffer, size)) return 0;
+    ply_reverse(anybuffer, size);
+    return 1;
+}
+
+static void ply_reverse(void *anydata, size_t size) {
+    char *data = (char *) anydata;
+    char temp;
+    size_t i;
+    for (i = 0; i < size/2; i++) {
+        temp = data[i];
+        data[i] = data[size-i-1];
+        data[size-i-1] = temp;
+    }
+}
+
+static void ply_init(p_ply ply) {
+    ply->c = ' ';
+    ply->element = NULL;
+    ply->nelements = 0;
+    ply->comment = NULL;
+    ply->ncomments = 0;
+    ply->obj_info = NULL;
+    ply->nobj_infos = 0;
+    ply->idriver = NULL;
+    ply->odriver = NULL;
+    ply->buffer[0] = '\0';
+    ply->buffer_first = ply->buffer_last = ply->buffer_token = 0;
+    ply->welement = 0;
+    ply->wproperty = 0;
+    ply->winstance_index = 0;
+    ply->wlength = 0;
+    ply->wvalue_index = 0;
+}
+
+static void ply_element_init(p_ply_element element) {
+    element->name[0] = '\0';
+    element->ninstances = 0;
+    element->property = NULL;
+    element->nproperties = 0; 
+}
+
+static void ply_property_init(p_ply_property property) {
+    property->name[0] = '\0';
+    property->type = -1;
+    property->length_type = -1;
+    property->value_type = -1;
+    property->read_cb = (p_ply_read_cb) NULL;
+    property->pdata = NULL;
+    property->idata = 0;
+}
+
+static p_ply ply_alloc(void) {
+    p_ply ply = (p_ply) malloc(sizeof(t_ply));
+    if (!ply) return NULL;
+    ply_init(ply);
+    return ply;
+}
+
+static void *ply_grow_array(p_ply ply, void **pointer, 
+        long *nmemb, long size) {
+    void *temp = *pointer;
+    long count = *nmemb + 1;
+    if (!temp) temp = malloc(count*size);
+    else temp = realloc(temp, count*size);
+    if (!temp) {
+        ply_error(ply, "Out of memory");
+        return NULL;
+    }
+    *pointer = temp;
+    *nmemb = count;
+    return (char *) temp + (count-1) * size;
+}
+
+static p_ply_element ply_grow_element(p_ply ply) {
+    p_ply_element element = NULL;
+    assert(ply); 
+    assert(ply->element || ply->nelements == 0); 
+    assert(!ply->element || ply->nelements > 0); 
+    element = (p_ply_element) ply_grow_array(ply, (void **) &ply->element, 
+            &ply->nelements, sizeof(t_ply_element));
+    if (!element) return NULL;
+    ply_element_init(element);
+    return element; 
+}
+
+static p_ply_property ply_grow_property(p_ply ply, p_ply_element element) {
+    p_ply_property property = NULL;
+    assert(ply);
+    assert(element);
+    assert(element->property || element->nproperties == 0);
+    assert(!element->property || element->nproperties > 0);
+    property = (p_ply_property) ply_grow_array(ply, 
+            (void **) &element->property, 
+            &element->nproperties, sizeof(t_ply_property));
+    if (!property) return NULL;
+    ply_property_init(property);
+    return property;
+}
+
+static int ply_read_header_format(p_ply ply) {
+    assert(ply && ply->fp && ply->io_mode == PLY_READ);
+    if (strcmp(BWORD(ply), "format")) return 0;
+    if (!ply_read_word(ply)) return 0;
+    ply->storage_mode = ply_find_string(BWORD(ply), ply_storage_mode_list);
+    if (ply->storage_mode == (e_ply_storage_mode) (-1)) return 0;
+    if (ply->storage_mode == PLY_ASCII) ply->idriver = &ply_idriver_ascii;
+    else if (ply->storage_mode == ply_arch_endian()) 
+        ply->idriver = &ply_idriver_binary;
+    else ply->idriver = &ply_idriver_binary_reverse;
+    if (!ply_read_word(ply)) return 0;
+    if (strcmp(BWORD(ply), "1.0")) return 0;
+    if (!ply_read_word(ply)) return 0;
+    return 1;
+}
+
+static int ply_read_header_comment(p_ply ply) {
+    assert(ply && ply->fp && ply->io_mode == PLY_READ);
+    if (strcmp(BWORD(ply), "comment")) return 0;
+    if (!ply_read_line(ply)) return 0;
+    if (!ply_add_comment(ply, BLINE(ply))) return 0;
+    if (!ply_read_word(ply)) return 0;
+    return 1;
+}
+
+static int ply_read_header_obj_info(p_ply ply) {
+    assert(ply && ply->fp && ply->io_mode == PLY_READ);
+    if (strcmp(BWORD(ply), "obj_info")) return 0;
+    if (!ply_read_line(ply)) return 0;
+    if (!ply_add_obj_info(ply, BLINE(ply))) return 0;
+    if (!ply_read_word(ply)) return 0;
+    return 1;
+}
+
+static int ply_read_header_property(p_ply ply) {
+    p_ply_element element = NULL;
+    p_ply_property property = NULL;
+    /* make sure it is a property */
+    if (strcmp(BWORD(ply), "property")) return 0;
+    element = &ply->element[ply->nelements-1];
+    property = ply_grow_property(ply, element);
+    if (!property) return 0;
+    /* get property type */
+    if (!ply_read_word(ply)) return 0;
+    property->type = ply_find_string(BWORD(ply), ply_type_list);
+    if (property->type == (e_ply_type) (-1)) return 0;
+    if (property->type == PLY_LIST) {
+        /* if it's a list, we need the base types */
+        if (!ply_read_word(ply)) return 0;
+        property->length_type = ply_find_string(BWORD(ply), ply_type_list);
+        if (property->length_type == (e_ply_type) (-1)) return 0;
+        if (!ply_read_word(ply)) return 0;
+        property->value_type = ply_find_string(BWORD(ply), ply_type_list);
+        if (property->value_type == (e_ply_type) (-1)) return 0;
+    }
+    /* get property name */
+    if (!ply_read_word(ply)) return 0;
+    strcpy(property->name, BWORD(ply));
+    if (!ply_read_word(ply)) return 0;
+    return 1;
+}
+
+static int ply_read_header_element(p_ply ply) {
+    p_ply_element element = NULL;
+    long dummy;
+    assert(ply && ply->fp && ply->io_mode == PLY_READ);
+    if (strcmp(BWORD(ply), "element")) return 0;
+    /* allocate room for new element */
+    element = ply_grow_element(ply);
+    if (!element) return 0;
+    /* get element name */
+    if (!ply_read_word(ply)) return 0;
+    strcpy(element->name, BWORD(ply));
+    /* get number of elements of this type */
+    if (!ply_read_word(ply)) return 0;
+    if (sscanf(BWORD(ply), "%ld", &dummy) != 1) {
+        ply_error(ply, "Expected number got '%s'", BWORD(ply));
+        return 0;
+    }
+    element->ninstances = dummy;
+    /* get all properties for this element */
+    if (!ply_read_word(ply)) return 0;
+    while (ply_read_header_property(ply) || 
+        ply_read_header_comment(ply) || ply_read_header_obj_info(ply))
+        /* do nothing */;
+    return 1;
+}
+
+static void ply_error_cb(const char *message) {
+    fprintf(stderr, "RPly: %s\n", message);
+}
+
+static void ply_error(p_ply ply, const char *fmt, ...) {
+    char buffer[1024];
+    va_list ap;
+    va_start(ap, fmt);
+    vsprintf(buffer, fmt, ap);
+    va_end(ap);
+    ply->error_cb(buffer);
+}
+
+static e_ply_storage_mode ply_arch_endian(void) {
+    unsigned long i = 1;
+    unsigned char *s = (unsigned char *) &i;
+    if (*s == 1) return PLY_LITTLE_ENDIAN;
+    else return PLY_BIG_ENDIAN;
+}
+
+static int ply_type_check(void) {
+    assert(sizeof(char) == 1);
+    assert(sizeof(unsigned char) == 1);
+    assert(sizeof(short) == 2);
+    assert(sizeof(unsigned short) == 2);
+    assert(sizeof(long) == 4);
+    assert(sizeof(unsigned long) == 4);
+    assert(sizeof(float) == 4);
+    assert(sizeof(double) == 8);
+    if (sizeof(char) != 1) return 0;
+    if (sizeof(unsigned char) != 1) return 0;
+    if (sizeof(short) != 2) return 0;
+    if (sizeof(unsigned short) != 2) return 0;
+    if (sizeof(long) != 4) return 0;
+    if (sizeof(unsigned long) != 4) return 0;
+    if (sizeof(float) != 4) return 0;
+    if (sizeof(double) != 8) return 0;
+    return 1;
+}
+
+/* ----------------------------------------------------------------------
+ * Output handlers
+ * ---------------------------------------------------------------------- */
+static int oascii_int8(p_ply ply, double value) {
+    if (value > CHAR_MAX || value < CHAR_MIN) return 0;
+    return fprintf(ply->fp, "%d ", (char) value) > 0;
+}
+
+static int oascii_uint8(p_ply ply, double value) {
+    if (value > UCHAR_MAX || value < 0) return 0;
+    return fprintf(ply->fp, "%d ", (unsigned char) value) > 0;
+}
+
+static int oascii_int16(p_ply ply, double value) {
+    if (value > SHRT_MAX || value < SHRT_MIN) return 0;
+    return fprintf(ply->fp, "%d ", (short) value) > 0;
+}
+
+static int oascii_uint16(p_ply ply, double value) {
+    if (value > USHRT_MAX || value < 0) return 0;
+    return fprintf(ply->fp, "%d ", (unsigned short) value) > 0;
+}
+
+static int oascii_int32(p_ply ply, double value) {
+    if (value > LONG_MAX || value < LONG_MIN) return 0;
+    return fprintf(ply->fp, "%d ", (int) value) > 0;
+}
+
+static int oascii_uint32(p_ply ply, double value) {
+    if (value > ULONG_MAX || value < 0) return 0;
+    return fprintf(ply->fp, "%d ", (unsigned int) value) > 0;
+}
+
+static int oascii_float32(p_ply ply, double value) {
+    if (value < -FLT_MAX || value > FLT_MAX) return 0;
+    return fprintf(ply->fp, "%g ", (float) value) > 0;
+}
+
+static int oascii_float64(p_ply ply, double value) {
+    if (value < -DBL_MAX || value > DBL_MAX) return 0;
+    return fprintf(ply->fp, "%g ", value) > 0;
+}
+
+static int obinary_int8(p_ply ply, double value) {
+    char int8 = (char) value;
+    if (value > CHAR_MAX || value < CHAR_MIN) return 0;
+    return ply->odriver->ochunk(ply, &int8, sizeof(int8));
+}
+
+static int obinary_uint8(p_ply ply, double value) {
+    unsigned char uint8 = (unsigned char) value;
+    if (value > UCHAR_MAX || value < 0) return 0;
+    return ply->odriver->ochunk(ply, &uint8, sizeof(uint8)); 
+}
+
+static int obinary_int16(p_ply ply, double value) {
+    short int16 = (short) value;
+    if (value > SHRT_MAX || value < SHRT_MIN) return 0;
+    return ply->odriver->ochunk(ply, &int16, sizeof(int16));
+}
+
+static int obinary_uint16(p_ply ply, double value) {
+    unsigned short uint16 = (unsigned short) value;
+    if (value > USHRT_MAX || value < 0) return 0;
+    return ply->odriver->ochunk(ply, &uint16, sizeof(uint16)); 
+}
+
+static int obinary_int32(p_ply ply, double value) {
+    long int32 = (long) value;
+    if (value > LONG_MAX || value < LONG_MIN) return 0;
+    return ply->odriver->ochunk(ply, &int32, sizeof(int32));
+}
+
+static int obinary_uint32(p_ply ply, double value) {
+    unsigned long uint32 = (unsigned long) value;
+    if (value > ULONG_MAX || value < 0) return 0;
+    return ply->odriver->ochunk(ply, &uint32, sizeof(uint32));
+}
+
+static int obinary_float32(p_ply ply, double value) {
+    float float32 = (float) value;
+    if (value > FLT_MAX || value < -FLT_MAX) return 0;
+    return ply->odriver->ochunk(ply, &float32, sizeof(float32));
+}
+
+static int obinary_float64(p_ply ply, double value) {
+    return ply->odriver->ochunk(ply, &value, sizeof(value)); 
+}
+
+/* ----------------------------------------------------------------------
+ * Input  handlers
+ * ---------------------------------------------------------------------- */
+static int iascii_int8(p_ply ply, double *value) {
+    char *end;
+    if (!ply_read_word(ply)) return 0;
+    *value = strtol(BWORD(ply), &end, 10);
+    if (*end || *value > CHAR_MAX || *value < CHAR_MIN) return 0;
+    return 1;
+}
+
+static int iascii_uint8(p_ply ply, double *value) {
+    char *end;
+    if (!ply_read_word(ply)) return 0;
+    *value = strtol(BWORD(ply), &end, 10);
+    if (*end || *value > UCHAR_MAX || *value < 0) return 0;
+    return 1;
+}
+
+static int iascii_int16(p_ply ply, double *value) {
+    char *end;
+    if (!ply_read_word(ply)) return 0;
+    *value = strtol(BWORD(ply), &end, 10);
+    if (*end || *value > SHRT_MAX || *value < SHRT_MIN) return 0;
+    return 1;
+}
+
+static int iascii_uint16(p_ply ply, double *value) {
+    char *end;
+    if (!ply_read_word(ply)) return 0;
+    *value = strtol(BWORD(ply), &end, 10);
+    if (*end || *value > USHRT_MAX || *value < 0) return 0;
+    return 1;
+}
+
+static int iascii_int32(p_ply ply, double *value) {
+    char *end;
+    if (!ply_read_word(ply)) return 0;
+    *value = strtol(BWORD(ply), &end, 10);
+    if (*end || *value > LONG_MAX || *value < LONG_MIN) return 0;
+    return 1;
+}
+
+static int iascii_uint32(p_ply ply, double *value) {
+    char *end;
+    if (!ply_read_word(ply)) return 0;
+    *value = strtol(BWORD(ply), &end, 10);
+    if (*end || *value < 0) return 0;
+    return 1;
+}
+
+static int iascii_float32(p_ply ply, double *value) {
+    char *end;
+    if (!ply_read_word(ply)) return 0;
+    *value = strtod(BWORD(ply), &end);
+    if (*end || *value < -FLT_MAX || *value > FLT_MAX) return 0;
+    return 1;
+}
+
+static int iascii_float64(p_ply ply, double *value) {
+    char *end;
+    if (!ply_read_word(ply)) return 0;
+    *value = strtod(BWORD(ply), &end);
+    if (*end || *value < -DBL_MAX || *value > DBL_MAX) return 0;
+    return 1;
+}
+
+static int ibinary_int8(p_ply ply, double *value) {
+    char int8;
+    if (!ply->idriver->ichunk(ply, &int8, 1)) return 0;
+    *value = int8;
+    return 1;
+}
+
+static int ibinary_uint8(p_ply ply, double *value) {
+    unsigned char uint8;
+    if (!ply->idriver->ichunk(ply, &uint8, 1)) return 0;
+    *value = uint8;
+    return 1;
+}
+
+static int ibinary_int16(p_ply ply, double *value) {
+    short int16;
+    if (!ply->idriver->ichunk(ply, &int16, sizeof(int16))) return 0;
+    *value = int16;
+    return 1;
+}
+
+static int ibinary_uint16(p_ply ply, double *value) {
+    unsigned short uint16;
+    if (!ply->idriver->ichunk(ply, &uint16, sizeof(uint16))) return 0;
+    *value = uint16;
+    return 1;
+}
+
+static int ibinary_int32(p_ply ply, double *value) {
+    long int32;
+    if (!ply->idriver->ichunk(ply, &int32, sizeof(int32))) return 0;
+    *value = int32;
+    return 1;
+}
+
+static int ibinary_uint32(p_ply ply, double *value) {
+    unsigned long uint32;
+    if (!ply->idriver->ichunk(ply, &uint32, sizeof(uint32))) return 0;
+    *value = uint32;
+    return 1;
+}
+
+static int ibinary_float32(p_ply ply, double *value) {
+    float float32;
+    if (!ply->idriver->ichunk(ply, &float32, sizeof(float32))) return 0;
+    *value = float32;
+    ply_reverse(&float32, sizeof(float32));
+    return 1;
+}
+
+static int ibinary_float64(p_ply ply, double *value) {
+    return ply->idriver->ichunk(ply, value, sizeof(double));
+}
+
+/* ----------------------------------------------------------------------
+ * Constants
+ * ---------------------------------------------------------------------- */
+static t_ply_idriver ply_idriver_ascii = {
+    {   iascii_int8, iascii_uint8, iascii_int16, iascii_uint16,
+        iascii_int32, iascii_uint32, iascii_float32, iascii_float64,
+        iascii_int8, iascii_uint8, iascii_int16, iascii_uint16,
+        iascii_int32, iascii_uint32, iascii_float32, iascii_float64
+    }, /* order matches e_ply_type enum */
+    NULL,
+    "ascii input"
+};
+
+static t_ply_idriver ply_idriver_binary = {
+    {   ibinary_int8, ibinary_uint8, ibinary_int16, ibinary_uint16,
+        ibinary_int32, ibinary_uint32, ibinary_float32, ibinary_float64,
+        ibinary_int8, ibinary_uint8, ibinary_int16, ibinary_uint16,
+        ibinary_int32, ibinary_uint32, ibinary_float32, ibinary_float64
+    }, /* order matches e_ply_type enum */
+    ply_read_chunk,
+    "binary input"
+};
+
+static t_ply_idriver ply_idriver_binary_reverse = {
+    {   ibinary_int8, ibinary_uint8, ibinary_int16, ibinary_uint16,
+        ibinary_int32, ibinary_uint32, ibinary_float32, ibinary_float64,
+        ibinary_int8, ibinary_uint8, ibinary_int16, ibinary_uint16,
+        ibinary_int32, ibinary_uint32, ibinary_float32, ibinary_float64
+    }, /* order matches e_ply_type enum */
+    ply_read_chunk_reverse,
+    "reverse binary input"
+};
+
+static t_ply_odriver ply_odriver_ascii = {
+    {   oascii_int8, oascii_uint8, oascii_int16, oascii_uint16,
+        oascii_int32, oascii_uint32, oascii_float32, oascii_float64,
+        oascii_int8, oascii_uint8, oascii_int16, oascii_uint16,
+        oascii_int32, oascii_uint32, oascii_float32, oascii_float64
+    }, /* order matches e_ply_type enum */
+    NULL,
+    "ascii output"
+};
+
+static t_ply_odriver ply_odriver_binary = {
+    {   obinary_int8, obinary_uint8, obinary_int16, obinary_uint16,
+        obinary_int32, obinary_uint32, obinary_float32, obinary_float64,
+        obinary_int8, obinary_uint8, obinary_int16, obinary_uint16,
+        obinary_int32, obinary_uint32, obinary_float32, obinary_float64
+    }, /* order matches e_ply_type enum */
+    ply_write_chunk,
+    "binary output"
+};
+
+static t_ply_odriver ply_odriver_binary_reverse = {
+    {   obinary_int8, obinary_uint8, obinary_int16, obinary_uint16,
+        obinary_int32, obinary_uint32, obinary_float32, obinary_float64,
+        obinary_int8, obinary_uint8, obinary_int16, obinary_uint16,
+        obinary_int32, obinary_uint32, obinary_float32, obinary_float64
+    }, /* order matches e_ply_type enum */
+    ply_write_chunk_reverse,
+    "reverse binary output"
+};
+
+/* ----------------------------------------------------------------------
+ * Copyright (C) 2003 Diego Nehab.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * ---------------------------------------------------------------------- */
Index: /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/rply.h
===================================================================
--- /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/rply.h	(revision 3357)
+++ /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/rply.h	(revision 3357)
@@ -0,0 +1,365 @@
+#ifndef PLY_H
+#define PLY_H
+/* ----------------------------------------------------------------------
+ * RPly library, read/write PLY files
+ * Diego Nehab, Princeton University
+ * http://www.cs.princeton.edu/~diego/professional/rply
+ *
+ * This library is distributed under the MIT License. See notice
+ * at the end of this file.
+ * ---------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RPLY_VERSION   "RPly 1.01"
+#define RPLY_COPYRIGHT "Copyright (C) 2003-2005 Diego Nehab"
+#define RPLY_AUTHORS   "Diego Nehab"
+
+/* ----------------------------------------------------------------------
+ * Types
+ * ---------------------------------------------------------------------- */
+/* structures are opaque */
+typedef struct t_ply_ *p_ply;
+typedef struct t_ply_element_ *p_ply_element;
+typedef struct t_ply_property_ *p_ply_property;
+typedef struct t_ply_argument_ *p_ply_argument;
+
+/* ply format mode type */
+typedef enum e_ply_storage_mode_ {
+    PLY_BIG_ENDIAN,
+    PLY_LITTLE_ENDIAN,
+    PLY_ASCII,   
+    PLY_DEFAULT      /* has to be the last in enum */
+} e_ply_storage_mode; /* order matches ply_storage_mode_list */
+
+/* ply data type */
+typedef enum e_ply_type {
+    PLY_INT8, PLY_UINT8, PLY_INT16, PLY_UINT16, 
+    PLY_INT32, PLY_UIN32, PLY_FLOAT32, PLY_FLOAT64,
+    PLY_CHAR, PLY_UCHAR, PLY_SHORT, PLY_USHORT,
+    PLY_INT, PLY_UINT, PLY_FLOAT, PLY_DOUBLE,
+    PLY_LIST    /* has to be the last in enum */
+} e_ply_type;   /* order matches ply_type_list */
+
+/* ----------------------------------------------------------------------
+ * Property reading callback prototype
+ *
+ * message: error message
+ * ---------------------------------------------------------------------- */
+typedef void (*p_ply_error_cb)(const char *message);
+
+/* ----------------------------------------------------------------------
+ * Opens a ply file for reading (fails if file is not a ply file)
+ *
+ * error_cb: error callback function
+ * name: file name
+ *
+ * Returns 1 if successful, 0 otherwise
+ * ---------------------------------------------------------------------- */
+p_ply ply_open(const char *name, p_ply_error_cb error_cb);
+
+/* ----------------------------------------------------------------------
+ * Reads and parses the header of a ply file returned by ply_open
+ *
+ * ply: handle returned by ply_open
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_read_header(p_ply ply);
+
+/* ----------------------------------------------------------------------
+ * Property reading callback prototype
+ *
+ * argument: parameters for property being processed when callback is called
+ *
+ * Returns 1 if should continue processing file, 0 if should abort.
+ * ---------------------------------------------------------------------- */
+typedef int (*p_ply_read_cb)(p_ply_argument argument);
+
+/* ----------------------------------------------------------------------
+ * Sets up callbacks for property reading after header was parsed
+ *
+ * ply: handle returned by ply_open
+ * element_name: element where property is
+ * property_name: property to associate element with
+ * read_cb: function to be called for each property value
+ * pdata/idata: user data that will be passed to callback
+ *
+ * Returns 0 if no element or no property in element, returns the
+ * number of element instances otherwise. 
+ * ---------------------------------------------------------------------- */
+long ply_set_read_cb(p_ply ply, const char *element_name, 
+        const char *property_name, p_ply_read_cb read_cb, 
+        void *pdata, long idata);
+
+/* ----------------------------------------------------------------------
+ * Returns information about the element originating a callback
+ *
+ * argument: handle to argument 
+ * element: receives a the element handle (if non-null)
+ * instance_index: receives the index of the current element instance 
+ *     (if non-null)
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_get_argument_element(p_ply_argument argument, 
+        p_ply_element *element, long *instance_index);
+
+/* ----------------------------------------------------------------------
+ * Returns information about the property originating a callback
+ *
+ * argument: handle to argument 
+ * property: receives the property handle (if non-null)
+ * length: receives the number of values in this property (if non-null)
+ * value_index: receives the index of current property value (if non-null)
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_get_argument_property(p_ply_argument argument, 
+        p_ply_property *property, long *length, long *value_index);
+
+/* ----------------------------------------------------------------------
+ * Returns user data associated with callback 
+ *
+ * pdata: receives a copy of user custom data pointer (if non-null)
+ * idata: receives a copy of user custom data integer (if non-null)
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_get_argument_user_data(p_ply_argument argument, void **pdata, 
+        long *idata);
+
+/* ----------------------------------------------------------------------
+ * Returns the value associated with a callback
+ *
+ * argument: handle to argument 
+ *
+ * Returns the current data item
+ * ---------------------------------------------------------------------- */
+double ply_get_argument_value(p_ply_argument argument); 
+
+/* ----------------------------------------------------------------------
+ * Reads all elements and properties calling the callbacks defined with
+ * calls to ply_set_read_cb
+ *
+ * ply: handle returned by ply_open
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_read(p_ply ply);
+
+/* ----------------------------------------------------------------------
+ * Iterates over all elements by returning the next element.
+ * Call with NULL to return handle to first element.
+ *
+ * ply: handle returned by ply_open
+ * last: handle of last element returned (NULL for first element)
+ *
+ * Returns element if successfull or NULL if no more elements
+ * ---------------------------------------------------------------------- */
+p_ply_element ply_get_next_element(p_ply ply, p_ply_element last);
+
+/* ----------------------------------------------------------------------
+ * Iterates over all comments by returning the next comment.
+ * Call with NULL to return pointer to first comment.
+ *
+ * ply: handle returned by ply_open
+ * last: pointer to last comment returned (NULL for first comment)
+ *
+ * Returns comment if successfull or NULL if no more comments
+ * ---------------------------------------------------------------------- */
+const char *ply_get_next_comment(p_ply ply, const char *last);
+
+/* ----------------------------------------------------------------------
+ * Iterates over all obj_infos by returning the next obj_info.
+ * Call with NULL to return pointer to first obj_info.
+ *
+ * ply: handle returned by ply_open
+ * last: pointer to last obj_info returned (NULL for first obj_info)
+ *
+ * Returns obj_info if successfull or NULL if no more obj_infos
+ * ---------------------------------------------------------------------- */
+const char *ply_get_next_obj_info(p_ply ply, const char *last);
+
+/* ----------------------------------------------------------------------
+ * Returns information about an element
+ *
+ * element: element of interest
+ * name: receives a pointer to internal copy of element name (if non-null)
+ * ninstances: receives the number of instances of this element (if non-null)
+ *
+ * Returns 1 if successfull or 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_get_element_info(p_ply_element element, const char** name,
+        long *ninstances);
+
+/* ----------------------------------------------------------------------
+ * Iterates over all properties by returning the next property.
+ * Call with NULL to return handle to first property.
+ *
+ * element: handle of element with the properties of interest
+ * last: handle of last property returned (NULL for first property)
+ *
+ * Returns element if successfull or NULL if no more properties
+ * ---------------------------------------------------------------------- */
+p_ply_property ply_get_next_property(p_ply_element element, 
+        p_ply_property last);
+
+/* ----------------------------------------------------------------------
+ * Returns information about a property
+ *
+ * property: handle to property of interest
+ * name: receives a pointer to internal copy of property name (if non-null)
+ * type: receives the property type (if non-null)
+ * length_type: for list properties, receives the scalar type of
+ *     the length field (if non-null)
+ * value_type: for list properties, receives the scalar type of the value 
+ *     fields  (if non-null)
+ *
+ * Returns 1 if successfull or 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_get_property_info(p_ply_property property, const char** name,
+        e_ply_type *type, e_ply_type *length_type, e_ply_type *value_type);
+
+/* ----------------------------------------------------------------------
+ * Creates new ply file
+ *
+ * name: file name
+ * storage_mode: file format mode
+ *
+ * Returns handle to ply file if successfull, NULL otherwise
+ * ---------------------------------------------------------------------- */
+p_ply ply_create(const char *name, e_ply_storage_mode storage_mode, 
+        p_ply_error_cb error_cb);
+
+/* ----------------------------------------------------------------------
+ * Adds a new element to the ply file created by ply_create
+ *
+ * ply: handle returned by ply_create
+ * name: name of new element
+ * ninstances: number of element of this time in file
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_add_element(p_ply ply, const char *name, long ninstances);
+
+/* ----------------------------------------------------------------------
+ * Adds a new property to the last element added by ply_add_element
+ *
+ * ply: handle returned by ply_create
+ * name: name of new property
+ * type: property type
+ * length_type: scalar type of length field of a list property 
+ * value_type: scalar type of value fields of a list property
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_add_property(p_ply ply, const char *name, e_ply_type type,
+        e_ply_type length_type, e_ply_type value_type);
+
+/* ----------------------------------------------------------------------
+ * Adds a new list property to the last element added by ply_add_element
+ *
+ * ply: handle returned by ply_create
+ * name: name of new property
+ * length_type: scalar type of length field of a list property 
+ * value_type: scalar type of value fields of a list property
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_add_list_property(p_ply ply, const char *name, 
+        e_ply_type length_type, e_ply_type value_type);
+
+/* ----------------------------------------------------------------------
+ * Adds a new property to the last element added by ply_add_element
+ *
+ * ply: handle returned by ply_create
+ * name: name of new property
+ * type: property type
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_add_scalar_property(p_ply ply, const char *name, e_ply_type type);
+
+/* ----------------------------------------------------------------------
+ * Adds a new comment item 
+ *
+ * ply: handle returned by ply_create
+ * comment: pointer to string with comment text
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_add_comment(p_ply ply, const char *comment);
+
+/* ----------------------------------------------------------------------
+ * Adds a new obj_info item 
+ *
+ * ply: handle returned by ply_create
+ * comment: pointer to string with obj_info data
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_add_obj_info(p_ply ply, const char *obj_info);
+
+/* ----------------------------------------------------------------------
+ * Writes the ply file header after all element and properties have been
+ * defined by calls to ply_add_element and ply_add_property
+ *
+ * ply: handle returned by ply_create
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_write_header(p_ply ply);
+
+/* ----------------------------------------------------------------------
+ * Writes one property value, in the order they should be written to the
+ * file. For each element type, write all elements of that type in order.
+ * For each element, write all its properties in order. For scalar
+ * properties, just write the value. For list properties, write the length 
+ * and then each of the values.
+ *
+ * ply: handle returned by ply_create
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_write(p_ply ply, double value);
+
+/* ----------------------------------------------------------------------
+ * Closes a ply file handle. Releases all memory used by handle
+ *
+ * ply: handle to be closed. 
+ *
+ * Returns 1 if successfull, 0 otherwise
+ * ---------------------------------------------------------------------- */
+int ply_close(p_ply ply);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPLY_H */
+
+/* ----------------------------------------------------------------------
+ * Copyright (C) 2003-2005 Diego Nehab. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * ---------------------------------------------------------------------- */
Index: /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/PlyConverter.cpp
===================================================================
--- /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/PlyConverter.cpp	(revision 3357)
+++ /GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/PlyConverter.cpp	(revision 3357)
@@ -0,0 +1,251 @@
+#include "PlyConverter.h"
+#include "SimpleTri.h"
+#include "SimpleVec.h"
+#include "gzstream.h"
+#include <iostream>
+#include "rply.h"
+
+
+using namespace std;
+
+static int sGlobalIndex = 0;
+
+
+VertexArray sVertices;
+VertexArray sNormals;
+
+
+PlyConverter::~PlyConverter()
+{
+	for (size_t i = 0; i < mGeometry.size(); ++ i) delete mGeometry[i];
+	mGeometry.clear();
+}
+
+
+void PlyConverter::LoadShape(const VertexArray &faceVertices,
+							 const VertexArray &faceNormals,
+							 const vector<Texcoord> &faceTexcoords
+							 )
+{
+	int numElements = (int)faceVertices.size();
+	Geometry *geom = new Geometry();
+/*
+	// convert the triangles to geometry
+	geom->mVertices = new SimpleVec[numElements];
+	geom->mNormals = new SimpleVec[numElements];
+	geom->mTexcoords = new Texcoord[numElements];
+
+	geom->mVertexCount = numElements;
+	geom->mTexcoordCount = (int)faceTexcoords.size();
+
+	cout << "creating new geometry with " << numElements << " vertices" << endl;
+
+	for (int i = 0; i < numElements; ++ i)
+	{
+		geom->mVertices[i] = faceVertices[i]
+		geom->mNormals[i] = faceNormals[i];
+
+		/*if (i < geom->mTexcoordCount)
+		{
+			geom->mTexcoords[i].first = faceTexcoords[i].first;
+			geom->mTexcoords[i].second = faceTexcoords[i].second;
+		}
+	}
+*/
+	mGeometry.push_back(geom);
+}
+
+
+bool PlyConverter::Convert(const string &filename, 
+						   const std::string &outputFilename)
+{
+	mNumShapes = 0;
+	
+	for (size_t i = 0; i < mGeometry.size(); ++ i) delete mGeometry[i];
+	mGeometry.clear();
+
+	if (!ReadFile(filename))
+	{
+		cerr << "could not read file" << endl;
+		return false;
+	}
+
+	if (!WriteFile(outputFilename))
+	{
+		cerr << "could not write file" << endl;
+		return false;
+	}
+
+	return true;
+}
+
+
+static int vertex_cb(p_ply_argument argument) 
+{
+    long eol;
+    ply_get_argument_user_data(argument, NULL, &eol);
+
+	static int mainIndex = 0;
+	static int i = 0;
+
+	static SimpleVec v;
+
+	v[i] = (float)ply_get_argument_value(argument);
+	//printf("here3 %g", ply_get_argument_value(argument));
+    
+	if (eol) sVertices.push_back(v);
+	i = (i + 1) % 3;
+	//else printf(" ");
+    
+	return 1;
+}
+
+
+static int face_cb(p_ply_argument argument) 
+{
+    long length, value_index;
+    ply_get_argument_property(argument, NULL, &length, &value_index);
+
+	switch (value_index) 
+	{
+        case 0:
+        case 1: 
+            printf("here4 %g ", ply_get_argument_value(argument));
+            break;
+        case 2:
+            printf("here5 %g\n", ply_get_argument_value(argument));
+            break;
+        default: 
+            break;
+    }
+    return 1;
+}
+
+
+
+bool PlyConverter::ReadFile(const string &filename) 
+{
+	long nvertices, ntriangles;
+
+	p_ply ply = ply_open(filename.c_str(), NULL);
+    
+	if (!ply) return 1;
+    if (!ply_read_header(ply)) return 1;
+    
+	nvertices = ply_set_read_cb(ply, "vertex", "x", vertex_cb, NULL, 0);
+
+    ply_set_read_cb(ply, "vertex", "y", vertex_cb, NULL, 0);
+    ply_set_read_cb(ply, "vertex", "z", vertex_cb, NULL, 1);
+
+	ntriangles = ply_set_read_cb(ply, "face", "vertex_indices", face_cb, NULL, 0);
+
+    printf("%ld\n%ld\n", nvertices, ntriangles);
+
+    if (!ply_read(ply)) return 1;
+    ply_close(ply);
+
+    return 0;
+}
+
+
+
+void PlyConverter::WriteGeometry(ogzstream &str, Geometry *geom)
+{
+	int vertexCount = (int)geom->mVertices.size();
+	str.write(reinterpret_cast<char *>(&vertexCount), sizeof(int));
+  
+	SimpleVec hvertices[3];
+	SimpleVec hnormals[3];
+
+	for (int i = 0; i < 3; ++ i)
+	{
+		hvertices[i] = geom->mVertices[i];
+		hnormals[i] = geom->mNormals[i];
+	}
+
+	int texCoordCount = 0;
+
+	str.write(reinterpret_cast<char *>(hvertices), sizeof(SimpleVec) * vertexCount);
+	str.write(reinterpret_cast<char *>(hnormals), sizeof(SimpleVec) * vertexCount);
+	str.write(reinterpret_cast<char *>(&texCoordCount), sizeof(int));
+
+	//if (texCoordCount) str.write(reinterpret_cast<char *>(geom->mTexcoords), sizeof(float) * texCoordCount * 2);
+}
+
+
+bool PlyConverter::WriteFile(const string &filename)
+{
+	ogzstream ofile(filename.c_str());
+
+	if (!ofile.is_open()) return false;
+	
+
+	/////////
+	//-- write textures
+
+#ifdef USE_TEXTURE
+	int textureCount = 1;
+#else
+	int textureCount = 0;
+#endif
+	ofile.write(reinterpret_cast<char *>(&textureCount), sizeof(int));
+
+	if (textureCount > 0)
+	{
+		// hack
+		const string texName("wood.jpg");
+
+		int texnameSize = (int)texName.length() + 1;
+		ofile.write(reinterpret_cast<char *>(&texnameSize), sizeof(int));
+
+		ofile.write(texName.c_str(), sizeof(char) * texnameSize);
+
+		int boundS = 1, boundT = 1;
+
+		ofile.write(reinterpret_cast<char *>(&boundS), sizeof(int));
+		ofile.write(reinterpret_cast<char *>(&boundT), sizeof(int));
+	}
+
+
+	///////////
+	//-- write shapes
+
+	ofile.write(reinterpret_cast<char *>(&mNumShapes), sizeof(int));
+
+	vector<Geometry *>::const_iterator it, it_end = mGeometry.end();
+
+	for (it = mGeometry.begin(); it != it_end; ++ it)
+	{
+		WriteGeometry(ofile, *it);
+	}
+
+
+	int entityCount = 1;
+	ofile.write(reinterpret_cast<char *>(&entityCount), sizeof(int));
+
+
+	//////////
+	//-- write single scene entity
+
+	// no transformation
+	bool hasTrafo = false;
+	ofile.write(reinterpret_cast<char *>(&hasTrafo), sizeof(bool));
+
+	// a dummy lod
+	int numLODs = 1;
+	ofile.write(reinterpret_cast<char *>(&numLODs), sizeof(int));
+
+	float dist = 0;
+	ofile.write(reinterpret_cast<char *>(&dist), sizeof(float));
+
+	ofile.write(reinterpret_cast<char *>(&mNumShapes), sizeof(int));
+
+	// all shapes belong to this scene entity
+	for (int i = 0; i < mNumShapes; ++ i)
+	{
+		int shapeId = i;
+		ofile.write(reinterpret_cast<char *>(&shapeId), sizeof(int));
+	}
+
+	return true;
+}
